思路:
树链剖分+修改版线段树,将所有点后移一位使编号从1到n,先剖分树链维护end[x]为x为根的子树中最后访问的点,再用线段树维护每一区间内已安装的包数。
最后回答问题时注意,安装应采用一段一段累加法,卸载应采用整段累加法。
#include<cstdio> #include<iostream> #include<vector> #include<cmath> #include<string> using namespace std; const int maxn = 100010; inline void qread(int &x){ x = 0; register int ch = getchar(), flag = 0; while(ch < '0' || ch > '9') { if(ch == '-') flag = 1; ch = getchar(); } while(ch >= '0' && ch <= '9') x = 10 * x + ch - 48, ch = getchar(); if(flag) x = -x; } int n, q, rt = 1; int head[maxn]; int nxt[maxn]; int f[maxn]; int deep[maxn]; int val[maxn]; int size[maxn]; int son[maxn]; int seg[maxn]; int rev[maxn]; int top[maxn]; int end[maxn]; int sum[maxn << 2]; int cov[maxn << 2]; void init(){ qread(n); for(int i=2; i<=n; ++i){ qread(f[i]); nxt[i] = head[++f[i]]; head[f[i]] = i; } qread(q); deep[1] = top[1] = seg[0] = seg[1] = rev[1] = 1; } void dfs1(int x){ size[x] = 1; for(register int i = head[x]; i; i=nxt[i]){ if(!deep[i]){ deep[i] = deep[x] + 1; dfs1(i); size[x] += size[i]; if(size[i] > size[son[x]]) son[x] = i; } } } void dfs2(int x){ end[x] = x; if(son[x]){ top[son[x]] = top[x]; seg[son[x]] = ++seg[0]; dfs2(son[x]); end[x] = end[son[x]]; } for(register int i = head[x]; i; i=nxt[i]) if(!top[i]){ top[i] = i; seg[i] = ++seg[0]; dfs2(i); end[x] = end[i]; } } inline void pushdown(int x, int t){ cov[x << 1] = cov[x]; cov[x << 1 | 1] = cov[x]; sum[x << 1] = (cov[x] - 1) * ((t + 1) >> 1); sum[x << 1 | 1] = (cov[x] - 1) * (t >> 1); cov[x] = 0; } void segcha(int l, int r, int L, int R, int v, int x){ if(L <= l && R >= r){ cov[x] = v; sum[x] = (v - 1) * (r - l + 1); return ; } if(cov[x]) pushdown(x, r - l + 1); int mid = (l + r) >> 1; if(mid >= L) segcha(l, mid, L, R, v, x << 1); if(mid < R) segcha(mid + 1, r, L, R, v, x << 1 | 1); sum[x] = sum[x << 1] + sum[x << 1 | 1]; } int segask(int l, int r, int L, int R, int x){ if(L <= l && R >= r) return sum[x]; if(cov[x]) pushdown(x, r - l + 1); int mid = (l + r) >> 1, ans = 0; if(mid >= L) ans += segask(l, mid, L, R, x << 1); if(mid < R) ans += segask(mid + 1, r, L, R, x << 1 | 1); return ans; } void show(int l, int r, int x){ cout << l << " " << r << " " << sum[x] << endl; if(l!=r){ int mid = (l + r) >> 1; show(l, mid, x << 1); show(mid + 1, r, x << 1 | 1); } } void SHOW(){ cout << "--" << endl; show(1, n, 1); cout << "--" << endl; } int ask(int x, int y, int v){ int fx = top[x], fy = top[y], ans = 0; if(deep[fx] < deep[fy]) swap(x, y), swap(fx, fy); while(fx != fy){ ans += segask(1, n, seg[fx], seg[x], 1); segcha(1, n, seg[fx], seg[x], v+1, 1); x = f[fx]; fx = top[x]; } if(deep[x] > deep[y]) swap(x, y); ans += segask(1, n, seg[x], seg[y], 1); segcha(1, n, seg[x], seg[y], v+1, 1); return ans; } int main(void){ init(); dfs1(1); dfs2(1); while(q--){ string op; cin >> op; if(op == "install"){ int x; qread(x); x++; printf("%d\n", deep[x] - ask(1, x, 1)); } else{ int x; qread(x); x++; printf("%d\n", segask(1, n, seg[x], seg[end[x]], 1)); segcha(1, n, seg[x], seg[end[x]], 0 + 1, 1); } } }