树链剖分入门好题!
我们将 $i$ 所依赖的软件包连向 $i$ 一条边,因为没有环而且仅依赖一个(只有一个父亲)所以这就形成了一棵树。
从根到节点 $x$ 的路径上的点就是建 $x$ 是所需要提前建好的。
节点 $x$ 的子树即为删去 $x$ 所需要提前删的。
这题线段树维护区间内有多少没被删的。
然后对于查询1查询路径 $1->x$ 得到路径上已经安装的软件包的个数 $num$,输出 $x$ 的深度减去 $num$即可。修改将路径 $1->x$ 上的所有数改成1(即安装)。
对于查询2,输出子树中有多少以安装的就行。修改就把子树全部改成0即可。
#include <iostream> #include <cstdio> using namespace std; const int N = 100010; struct node{ int pre, to; }edge[N]; int head[N], tot; struct seg_tree{ int val, tag, l, r; }st[4 * N]; int n, m; int sz[N]; int depend[N], pos[N], dfn, lst[N], bl[N], dep[N]; int read() { int ret = 0, f = 1; char ch = getchar(); while ('0' > ch || ch > '9') { if (ch == '-') { f = -1; } ch = getchar(); } while ('0' <= ch && ch <= '9') { ret = (ret << 1) + (ret << 3) + ch - '0'; ch = getchar(); } return ret * f; } void add(int u, int v) { edge[++tot] = node{head[u], v}; head[u] = tot; } void dfs1(int x) { sz[x] = 1; for (int i = head[x]; i; i = edge[i].pre) { int y = edge[i].to; dep[y] = dep[x] + 1; dfs1(y); sz[x] += sz[y]; } } void dfs2(int x, int chain) { pos[x] = lst[x] = ++dfn; bl[x] = chain; int k = n; for (int i = head[x]; i; i = edge[i].pre) { int y = edge[i].to; if (sz[y] > sz[k]) { k = y; } } if (k != n) dfs2(k, chain), lst[x] = max(lst[x], lst[k]); for (int i = head[x]; i; i = edge[i].pre) { int y = edge[i].to; if (y != k) { dfs2(y, y); lst[x] = max(lst[x], lst[y]); } } } void build(int x, int l, int r) { st[x].l = l, st[x].r = r; st[x].tag = -1; if (l == r) return; int mid = (l + r) >> 1; build(x << 1, l, mid); build(x << 1 | 1, mid + 1, r); } void update(int p) { if (st[p].tag != -1) { st[p << 1].tag = st[p].tag; st[p << 1 | 1].tag = st[p].tag; st[p << 1].val = (st[p << 1].r - st[p << 1].l + 1) * st[p].tag; st[p << 1 | 1].val = (st[p << 1 | 1].r - st[p << 1 | 1].l + 1) * st[p].tag; st[p].tag = -1; } } int ask(int p, int x, int y) { int l = st[p].l, r = st[p].r; if (x > r || y < l) return 0; if (x <= l && r <= y) { return st[p].val; } update(p); return ask(p << 1, x, y) + ask(p << 1 | 1, x, y); } void change(int p, int x, int y, int v) { int l = st[p].l, r = st[p].r; if (x > r || y < l) return; if (x <= l && r <= y) { st[p].tag = v; st[p].val = (r - l + 1) * v; return; } update(p); change(p << 1, x, y, v); change(p << 1 | 1, x, y, v); st[p].val = st[p << 1].val + st[p << 1 | 1].val; } int Q_sum(int u, int v) { int ret = 0; while (bl[u] != bl[v]) { if (dep[bl[u]] < dep[bl[v]]) swap(u, v); ret += ask(1, pos[bl[u]], pos[u]); u = depend[bl[u]]; } if (dep[u] > dep[v]) swap(u, v); ret += ask(1, pos[u], pos[v]); return ret; } void cc(int u, int v, int val) { while (bl[u] != bl[v]) { if (dep[bl[u]] < dep[bl[v]]) swap(u, v); change(1, pos[bl[u]], pos[u], val); u = depend[bl[u]]; } if (dep[u] > dep[v]) swap(u, v); change(1, pos[u], pos[v], val); } int main() { cin >> n; for (int i = 1; i < n; i++) { cin >> depend[i]; add(depend[i], i); } dfs1(0); dfs2(0, 0); build(1, 1, dfn); cin >> m; while (m--) { string opt; int x; cin >> opt; x = read(); if (opt == "install") { cout << dep[x] + 1 - Q_sum(0, x) << " "; cc(0, x, 1); } else { cout << ask(1, pos[x], lst[x]) << " "; change(1, pos[x], lst[x], 0); } } return 0; }