【题目链接】
【思路要点】
- 树链剖分,子树是DFS序中连续的一段,而路径由至多\(O(LogN)\)段组成,剩余部分用线段树解决即可。
- 时间复杂度\(O(QLog^{2}N)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 120000 struct node { int l, r, mid, lc, rc, size, sum; bool install, uninstall; }; int n, t, total; vector <int> a[MAXN]; int depth[MAXN], size[MAXN], father[MAXN], heavy_son[MAXN]; int new_num[MAXN], up[MAXN], right_num[MAXN]; node tree[MAXN * 2]; void push_down(int x) { if (tree[x].l == tree[x].r || tree[x].install == false && tree[x].uninstall == false) return; if (tree[x].install) { tree[tree[x].lc].install = true; tree[tree[x].lc].uninstall = false; tree[tree[x].lc].sum = tree[tree[x].lc].size; tree[tree[x].rc].install = true; tree[tree[x].rc].uninstall = false; tree[tree[x].rc].sum = tree[tree[x].rc].size; tree[x].install = false; } else { tree[tree[x].lc].uninstall = true; tree[tree[x].lc].install = false; tree[tree[x].lc].sum = 0; tree[tree[x].rc].uninstall = true; tree[tree[x].rc].install = false; tree[tree[x].rc].sum = 0; tree[x].uninstall = false; } } void maintain(int x, int l, int r, int type) { if (type == 1) { if (tree[x].l == l && tree[x].r == r) { tree[x].install = true; tree[x].uninstall = false; tree[x].sum = tree[x].size; return; } push_down(x); if (l <= tree[x].mid) maintain(tree[x].lc, l, min(r, tree[x].mid), type); if (r > tree[x].mid) maintain(tree[x].rc, max(l, tree[x].mid + 1), r, type); tree[x].sum = tree[tree[x].lc].sum + tree[tree[x].rc].sum; } else { if (tree[x].l == l && tree[x].r == r) { tree[x].uninstall = true; tree[x].install = false; tree[x].sum = 0; return; } push_down(x); if (l <= tree[x].mid) maintain(tree[x].lc, l, min(r, tree[x].mid), type); if (r > tree[x].mid) maintain(tree[x].rc, max(l, tree[x].mid + 1), r, type); tree[x].sum = tree[tree[x].lc].sum + tree[tree[x].rc].sum; } } int query(int x, int l, int r) { if (tree[x].l == l && tree[x].r == r) return tree[x].sum; push_down(x); int ans = 0; if (l <= tree[x].mid) ans += query(tree[x].lc, l, min(r, tree[x].mid)); if (r > tree[x].mid) ans += query(tree[x].rc, max(l, tree[x].mid + 1), r); return ans; } void build(int x, int l, int r) { tree[x].l = l; tree[x].r = r; tree[x].size = r - l + 1; tree[x].mid = (l + r) / 2; if (l == r) return; tree[x].lc = ++total; build(total, l, tree[x].mid); tree[x].rc = ++total; build(total, tree[x].mid + 1, r); } int Uninstall(int x) { int ans = query(1, new_num[x], right_num[x]); maintain(1, new_num[x], right_num[x], 0); return ans; } int Install(int x) { int ans = depth[x]; while (up[x] != 0) { ans -= query(1, new_num[up[x]], new_num[x]); maintain(1, new_num[up[x]], new_num[x], 1); x = up[x]; x = father[x]; } ans -= query(1, new_num[up[x]], new_num[x]); maintain(1, new_num[up[x]], new_num[x], 1); return ans; } void work(int x) { if (x != heavy_son[father[x]]) up[x] = x; else up[x] = up[father[x]]; new_num[x] = ++t; if (heavy_son[x] != 0) work(heavy_son[x]); for (unsigned i = 0; i<a[x].size(); i++) { if (a[x][i] != heavy_son[x]) work(a[x][i]); } right_num[x] = t; } void dfs(int x) { int maxnum = 0; depth[x] = depth[father[x]] + 1; size[x] = 1; for (unsigned i = 0; i < a[x].size(); i++) { dfs(a[x][i]); size[x] += size[a[x][i]]; if (size[a[x][i]] > maxnum) { maxnum = size[a[x][i]]; heavy_son[x] = a[x][i]; } } } int main() { int n; scanf("%d", &n); int i; for (i = 1; i < n; i++) { scanf("%d", &father[i]); a[father[i]].push_back(i); } dfs(0); work(0); total = 1; build(1, 1, n); int x, q; scanf("%d", &q); char s[10]; for (i = 1; i <= q; i++) { scanf("%s%d", s, &x); if (s[0] == 'i') printf("%d\n", Install(x)); else printf("%d\n", Uninstall(x)); } return 0; }