HDU 5221 Occupation dfs序版樹鏈剖分
阿新 • • 發佈:2019-02-13
題目大意:
就是現在給出一棵樹, 以1為根, 樹上的點都有自己的權值, 初始都沒有被佔領, 接下來3種操作
1. 從u到v的路徑上的所有點被M佔領
2. 某個點u被C佔領
3. 以u為根的子樹被M佔領
每次操作後輸出當前被M佔領的那些點的點權和
大致思路:
很明顯對於操作1和2用樹鏈剖分很容易處理
對於第3種操作, 需要利用樹的時間戳...於是這裡寫了一次dfs版的樹鏈剖分
也沒有什麼特別了的吧...我線段樹維護的時候記錄當前區間總和, 和被佔領的部分的總和, lazy標記時候被還原亦或被佔領
對於第1種操作單次時間複雜度O((logn)^2), 另外兩種單次時間複雜度都是O(logn)
程式碼如下:
Result : Accepted Memory : 13028 KB Time : 1528 ms
/* * Author: Gatevin * Created Time: 2015/9/10 23:13:50 * File Name: HLD_dfs.cpp */ #pragma comment(linker, "/STACK:102400000,102400000") #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define maxn 100010 int n; int w[maxn]; struct Edge { int u, v, nex; Edge(int _u, int _v, int _nex) { u = _u, v = _v, nex = _nex; } Edge(){} }; Edge edge[maxn << 1]; int tot; int head[maxn]; void add_Edge(int u, int v) { edge[++tot] = Edge(u, v, head[u]); head[u] = tot; } int father[maxn]; int dep[maxn]; int siz[maxn]; int hson[maxn];//u的重兒子為hson[u], 為-1表示沒有 int top[maxn];//top[u]表示結點u所在鏈的頂端結點 int L[maxn], R[maxn];//[L[u], R[u]]代表結點u的dfs序時間戳 int antiID[maxn];//antiID[x]表示樹上那個結點在區間上位置是x //在dfs的方式下, 沒有用id[x]表示結點x所在的區間位置, 因為L[]陣列代替了這個作用 int tim;//時間戳時間 void dfs1(int now) { siz[now] = 1; hson[now] = -1; int nex; for(int i = head[now]; i + 1; i = edge[i].nex) if((nex = edge[i].v) != father[now]) { father[nex] = now; dep[nex] = dep[now] + 1; dfs1(nex); siz[now] += siz[nex]; if(hson[now] == -1 || siz[nex] > siz[hson[now]]) hson[now] = nex; } } void dfs2(int now, int tp) { L[now] = ++tim; top[now] = tp; antiID[tim] = now; if(hson[now] != -1) dfs2(hson[now], tp); int nex; for(int i = head[now]; i + 1; i = edge[i].nex) if((nex = edge[i].v) != father[now] && nex != hson[now]) dfs2(nex, nex); R[now] = tim; } void split() { tim = 0; father[1] = -1; dep[1] = 1; dfs1(1); dfs2(1, 1); } int ans; //Segment_Tree #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 int sum[maxn << 2];//當前區間總和 int occupy[maxn << 2];//當前結點代表的區間已經佔領的和 int lazy[maxn << 2];// void pushUp(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; occupy[rt] = occupy[rt << 1] + occupy[rt << 1 | 1]; } void pushDown(int rt) { if(lazy[rt] == 1) { lazy[rt << 1] = lazy[rt << 1 | 1] = 1; occupy[rt << 1] = sum[rt << 1]; occupy[rt << 1 | 1] = sum[rt << 1 | 1]; lazy[rt] = 0; } if(lazy[rt] == 2) { lazy[rt << 1] = lazy[rt << 1 | 1] = 2; lazy[rt] = 0; occupy[rt << 1] = occupy[rt << 1 | 1] = 0; } } void build(int l, int r, int rt) { sum[rt] = 0, occupy[rt] = 0, lazy[rt] = 0; if(l == r) { sum[rt] = w[antiID[l]]; return; } int mid = (l + r) >> 1; build(lson); build(rson); pushUp(rt); } void update(int l, int r, int rt, int L, int R, int state)//state == 1更新為佔用, 否則不佔用 { if(l >= L && r <= R) { if(state == 1) { ans += sum[rt] - occupy[rt]; occupy[rt] = sum[rt]; lazy[rt] = 1; } else { ans -= occupy[rt]; occupy[rt] = 0; lazy[rt] = 2; } return; } int mid = (l + r) >> 1; pushDown(rt); if(mid >= L) update(lson, L, R, state); if(mid + 1 <= R) update(rson, L, R, state); pushUp(rt); } void modify(int x, int y)//更新x到y的路徑為M佔用 { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x, y); update(1, n, 1, L[top[x]], L[x], 1); x = father[top[x]]; } if(dep[x] > dep[y]) swap(x, y); update(1, n, 1, L[x], L[y], 1); } int main() { int T; scanf("%d", &T); while(T--) { tot = 0; memset(head, -1, sizeof(head)); scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", w + i); int u, v; for(int i = 1; i < n; i++) { scanf("%d %d", &u, &v); add_Edge(u, v); add_Edge(v, u); } split(); build(1, n, 1); ans = 0; int Q; scanf("%d", &Q); while(Q--) { int op; scanf("%d", &op); switch(op) { case 1: scanf("%d %d", &u, &v); modify(u, v);//u和v之間的路徑被M佔領 break; case 2: scanf("%d", &u); update(1, n, 1, L[u], L[u], 0);//u被C佔領 break; case 3: scanf("%d", &u); update(1, n, 1, L[u], R[u], 1);//M佔領u為根的子樹 break; } printf("%d\n", ans); } } return 0; }