日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU 6203 贪心 + LCA + dfs序 + BIT

發(fā)布時間:2024/3/26 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU 6203 贪心 + LCA + dfs序 + BIT 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

簡要題意:給出一個n+1個點的樹,以及若干個點對,需要斷開一些點,使得這些點對路徑不連通。輸出應該斷開的最少點數(shù)。

我們斷開一個點,能夠影響到的是:
1.子樹中過這個點的路徑.
2.一個點在子樹中,另一個點在祖先中的路徑。

為了使得以上兩個影響盡可能的大,我們每次需要使得斷開的點的子樹盡可能大。
因此當我們打算斷開一對點對(u,v)的時候,為了使得斷開的點的影響盡可能大,我們需要斷開路徑上深度最小的那個點,也就是lca(u,v)

①. 如果一對點對(u,v)的其中一個點在某個被斷開的點的子樹中,而另一個點不在,則說明這兩點間的路徑經(jīng)過被斷開點,那么這條路徑就沒有再次斷開的必要了。
②. 如果一對點對兩個點都不在任何已經(jīng)被斷開的點的子樹中,則說明這兩個點的lca還需要被斷開。
事實上還有一種情況, 如果兩個點都被覆蓋了,則可能出現(xiàn)的情況是,兩個點之間的路徑都被覆蓋了,但是卻沒有一個點被斷開。對于這種情況我們也需要將兩點間的lca斷開。但是我們斷開這次lca之后,有可能會導致之前我們處理過的,本該被判定為情況①,因為處理順序的緣故被判定為情況②,從而導致結果偏大。因此為了避免這種情況,需要離線詢問,按lca的深度從大到小來處理。

判定一個點是否在某個被斷開的點的子樹中,只需要看這個點是否被標記過。
每次斷開一個點,都需要把這個點的子樹里的點都標記上。對于這種對子樹的簡單操作,一般我們都使用dfs序,更麻煩一些的,使用樹鏈剖分。
使用了dfs序之后,給子樹標記可以使用線段樹。不過我們只需要知道一個點是否被標記過,因此使用樹狀數(shù)組即可。

#include <bits/stdc++.h>using namespace std;const int maxn = 110000;int p[maxn][20], deep[maxn], L[maxn], R[maxn], cid; vector<int> G[maxn];void dfs(int u, int fa) {p[u][0] = fa;L[u] = ++cid;deep[u] = deep[fa] + 1;for(auto v : G[u]) {if(v == fa) continue;dfs(v, u);}R[u] = cid; }int goup(int x, int len) {for(int i = 0; i < 20; i++) {if(len & (1 << i) && x)x = p[x][i];}return x; }int lca(int u, int v) {if(deep[u] < deep[v]) swap(u, v);int d = deep[u] - deep[v];u = goup(u, d);if(v == u) return u;for(int i = 19; i >= 0; i--) {if(p[u][i] == p[v][i]) continue;u = p[u][i];v = p[v][i];}return p[u][0]; }namespace BIT {int C[maxn];void init() {memset(C, 0, sizeof C);}int lowbit(int x) {return x & -x;}void ins(int x, int v) {for(int i = x; i < maxn; i+=lowbit(i))C[i] += v;}int ask(int x) {int res = 0;for(int i = x; i; i-=lowbit(i))res += C[i];return res;} }struct A {int u, v, lc, lcdep;bool operator < (const A & b) const {return lcdep > b.lcdep;} };void init() {for(int i = 0; i < maxn; i++) G[i].clear();deep[0] = 0;cid = 0; }int main() {int n;while(~scanf("%d", &n)) {init();for(int i = 1; i <= n; i++) {int x, y;scanf("%d%d", &x, &y);x ++, y++;G[x].push_back(y);G[y].push_back(x);}n++;dfs(1, 0);for(int i = 1; i < 20; i++) {for(int j = 1; j <= n; j++) {if(p[j][i-1] == 0) p[j][i] = 0;else p[j][i] = p[p[j][i-1]][i-1];}}int q;scanf("%d", &q);vector<A> V;while(q--) {int x, y;scanf("%d%d", &x, &y);x++, y++;int lc = lca(x, y);V.push_back({x, y, lc, deep[lc]});}sort(V.begin(), V.end());int ans = 0;BIT::init();for(int i = 0; i < V.size(); i++) {int u = V[i].u, v = V[i].v, lc = V[i].lc;if(BIT::ask(L[u]) || BIT::ask(L[v])) continue;BIT::ins(L[lc], 1);BIT::ins(R[lc] + 1, -1); ans++;}printf("%d\n", ans);}return 0; }

總結

以上是生活随笔為你收集整理的HDU 6203 贪心 + LCA + dfs序 + BIT的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。