题目大意
有一颗依赖关系构成的一颗树,有两个操作
install
,把从 x 到根节点这一条链全都改为 1uninstall
,把以 x 为根的子树全都变成 0
现在求每个操作会改变多少节点的值
题解
标准树剖,但是细节很多
- 懒标记开始为 -1,下传后也要变成 -1
- 聪明的做法:先记录操作之前 1 的个数,在查询操作后的个数,然后输出差值
Code
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,T,lst[N],nxt[N<<1],to[N<<1],cnt,odd,dfn[N],sz[N],top[N],dep[N],fa[N],son[N],sm[N<<3],tg[N<<3];
inline void Ae(int fr,int go) { to[++cnt]=go,nxt[cnt]=lst[fr],lst[fr]=cnt; }
char opt[15];
void Get(int u,int f) {
sz[u]=1,dep[u]=dep[fa[u]=f]+1;
for(int i=lst[u];i;i=nxt[i])
if(to[i]^f) {
Get(to[i],u),sz[u]+=sz[to[i]];
if(sz[to[i]]>sz[son[u]])son[u]=to[i];
}
}
void Dfs(int u,int nw) {
top[u]=nw,dfn[u]=++odd;
if(!son[u])return; Dfs(son[u],nw);
for(int i=lst[u];i;i=nxt[i])
if(to[i]^fa[u] && to[i]^son[u])Dfs(to[i],to[i]);
}
inline void Up(int rt) { sm[rt]=sm[rt<<1]+sm[rt<<1|1]; }
void Build(int l,int r,int rt) {
if(l==r)return; register int mid=l+r>>1;
Build(l,mid,rt<<1),Build(mid+1,r,rt<<1|1);
}
inline void Down(int rt,int len) {
sm[rt<<1]=(len+1>>1)*tg[rt],tg[rt<<1]=tg[rt];
sm[rt<<1|1]=(len>>1)*tg[rt],tg[rt<<1|1]=tg[rt],tg[rt]=-1;
}
void Modify(int ql,int qr,int vl,int l,int r,int rt) {
if(ql<=l && r<=qr) { sm[rt]=vl*(r-l+1),tg[rt]=vl; return; }
register int mid=l+r>>1; if(tg[rt]!=-1)Down(rt,r-l+1);
if(ql<=mid)Modify(ql,qr,vl,l,mid,rt<<1);
if(qr>mid)Modify(ql,qr,vl,mid+1,r,rt<<1|1); Up(rt);
}
inline void Change(int x) {
for(;top[x]^top[1];x=fa[top[x]])
Modify(dfn[top[x]],dfn[x],1,1,n,1);
Modify(1,dfn[x],1,1,n,1);
}
int main() {
freopen("manager.in","r",stdin);
freopen("manager.out","w",stdout);
scanf("%d",&n);
for(int i=2,u;i<=n;i++) {
scanf("%d",&u),++u;
Ae(i,u),Ae(u,i);
}
Get(1,0),Dfs(1,1),Build(1,n,1);
scanf("%d",&T);
for(int u,pr,ft;T--;) {
scanf("%s%d",opt,&u),++u;
pr=sm[1];
if(opt[0]=='i')Change(u);
else if(opt[0]=='u')Modify(dfn[u],dfn[u]+sz[u]-1,0,1,n,1);
ft=sm[1];
printf("%d
",abs(pr-ft));
}
}