给出一棵以 \(1\) 为根的树,每个结点有一个状态为 \(1\) 或 \(0\) ,初始时为 \(0\) ,给出两种操作,一种询问结点 \(x\) 到根结点路径上状态为 \(0\) 的结点数,并将他们的状态变为 \(0\) ,一种询问结点 \(x\) 的子树内状态为 \(1\) 的结点数,并将他们的状态变为 \(0\) 。 \((1\le n,q\le 100,000)\)
分析
我们用 \(dep_i\) 来记录 \(i\) 的深度,设 \(k\) 为 \(u\) 到根结点路径上的状态和,那么对于第一种操作的答案即为 \(dep_u-k\) ,用一棵线段树来维护每个结点的状态值和区间状态和,因为询问和修改是同时进行的,我们可以把询问和修改的函数写成一个函数。
对于第一种操作,我们利用树链剖分,每次统计 \(u\) 到 \(top[u]\) 的答案并修改,直到统计完 \(top[u]=1\) 时的答案即可。对于第二种操作,直接利用 \(dfs\) 序计算答案。
注意,输入的结点编号是从 \(0\) 开始的,所以我把所有输入的结点编号都 \(+1\) 了。
代码
#include <bits/stdc++.h>
#define N 100003
#define ls (o<<1)
#define rs (o<<1|1)
#define rg register
#define DEBUG puts("ok")
using namespace std;
inline int gi() {
rg int x = 0, f = 1; rg char c = getchar();
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
struct Segment { int l, r, sum, tg; } tr[N << 2];
int n, q, tot;
int hd[N], nxt[N];
int dep[N], dfn[N], st[N], ed[N], fa[N], top[N], son[N], sz[N];
inline void insert(int u, int v) { nxt[u] = hd[v], hd[v] = u; }
inline void dfs(int u, int f) {
dep[u] = dep[f] + 1, fa[u] = f, sz[u] = 1;
for (rg int v = hd[u]; v; v = nxt[v]) {
dfs(v, u);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
inline void dfs2(int u, int tp) {
top[u] = tp;
dfn[++tot] = u, st[u] = tot;
if (son[u]) dfs2(son[u], tp);
for (rg int v = hd[u]; v; v = nxt[v])
if (v != son[u]) dfs2(v, v);
ed[u] = tot;
}
inline void pushup(int o) { tr[o].sum = tr[ls].sum + tr[rs].sum; }
inline void pushdown(int o) {
if (tr[o].tg != -1) {
tr[ls].tg = tr[rs].tg = tr[o].tg;
tr[ls].sum = tr[o].tg * (tr[ls].r - tr[ls].l + 1);
tr[rs].sum = tr[o].tg * (tr[rs].r - tr[rs].l + 1);
tr[o].tg = -1;
}
}
inline void build(int o, int l, int r) {
tr[o].l = l, tr[o].r = r, tr[o].tg = -1;
if (l == r) return;
rg int mid = l + r >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
}
inline int query(int o, int l, int r, int L, int R, int k) {
if (l >= L && r <= R) {
rg int tmp = tr[o].sum;
tr[o].tg = k, tr[o].sum = (tr[o].r - tr[o].l + 1) * k;
return tmp;
}
pushdown(o);
rg int mid = l + r >> 1, ret = 0;
if (L <= mid) ret += query(ls, l, mid, L, R, k);
if (R > mid) ret += query(rs, mid + 1, r, L, R, k);
pushup(o);
return ret;
}
inline int install(int x) {
rg int tx = 0, ret = 0;
while (tx != 1) {
tx = top[x];
rg int tmp = dep[x] - dep[tx] + 1;
ret += tmp - query(1, 1, n, st[tx], st[x], 1);
x = fa[tx];
}
return ret;
}
int main() {
rg int x; rg char op[10];
n = gi();
for (rg int i = 2; i <= n; ++i) {
x = gi() + 1;
insert(i, x);
}
dfs(1, 0);
dfs2(1, 1);
build(1, 1, n);
q = gi();
for (rg int i = 1; i <= q; ++i) {
scanf("%s", op);
x = gi() + 1;
if (op[0] == 'i') printf("%d\n", install(x));
else printf("%d\n", query(1, 1, n, st[x], ed[x], 0));
}
return 0;
}