很好的树剖板子题:
操作一:求点x到0的最短路径 经过的结点个数-路径上已安装的软件包的总个数,同时将经过的路径上的所有点标记为已安装。
操作二:将子树代表的那段存安装包个数的区间清空(或者是说将其sum值赋值为0)。
此处为了实现标记已安装和清空,我们用了一个标记add:
add[i]=1:线段树上的点i及其子区间全被赋值为len[];
add[i]=2:线段树上的点i及其子区间全被赋值为0;
这里add的下放和普通的线段树下放一样,原理相同,但注意add值为0时不要pushdown(防止覆盖子区间原有的add标记)。
代码:
#include<cstdio>
#include<iostream>
#include<string>
#define ri register int
using namespace std;
const int MAXN=200020;
int n,m,q,num,u[MAXN],v[MAXN],fst[MAXN],nxt[MAXN];
int fa[MAXN],deep[MAXN],siz[MAXN],cmax[MAXN],son[MAXN],top[MAXN],cnt,dfn[MAXN];
int l[MAXN<<2],r[MAXN<<2],sum[MAXN<<2],clean[MAXN<<2],had[MAXN<<2],add[MAXN<<2];
string ss;
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||'9'<ch) ch=getchar();
while('0'<=ch&&ch<='9')
{
x=(x <<3)+(x <<1)+(ch-'0');
ch=getchar();
}
return x;
}
void dfs1(int x,int father,int dep)
{
fa[x]=father,deep[x]=dep,siz[x]=1;
for(ri k=fst[x];k>0;k=nxt[k])
if(v[k]!=father)
{
dfs1(v[k],x,dep+1);
if(siz[v[k]]>cmax[x]) cmax[x]=siz[v[k]],son[x]=v[k];
siz[x]+=siz[v[k]];
}
}
void dfs2(int x,int anc)
{
top[x]=anc,dfn[x]=++cnt;
if(son[x]) dfs2(son[x],anc);
for(ri k=fst[x];k>0;k=nxt[k])
if(v[k]!=fa[x]&&v[k]!=son[x]) dfs2(v[k],v[k]);
}
void pushup(int p)
{
sum[p]=sum[p <<1]+sum[p <<1|1];
}
void pushdown(int p)
{
if(add[p]==1)
{
sum[p <<1]=r[p <<1]-l[p <<1]+1;
sum[p <<1|1]=r[p <<1|1]-l[p <<1|1]+1;
}
if(add[p]==2)
{
sum[p <<1]=0;
sum[p <<1|1]=0;
}
add[p <<1]=add[p],add[p <<1|1]=add[p];
add[p]=0;
}
void build(int p,int lft,int rit)
{
l[p]=lft,r[p]=rit;
if(l[p]==r[p]) return;
int mid=(lft+rit)>>1;
build(p <<1,lft,mid);
build(p <<1|1,mid+1,rit);
}
void update(int p,int lft,int rit,int tag)
{
if(lft<=l[p]&&r[p]<=rit)
{
if(tag==1) sum[p]=r[p]-l[p]+1;
if(tag==2) sum[p]=0;
add[p]=tag;
return;
}
if(add[p]>0) pushdown(p);
if(lft<=r[p <<1]) update(p <<1,lft,rit,tag);
if(l[p <<1|1]<=rit) update(p <<1|1,lft,rit,tag);
pushup(p);
}
int query(int p,int lft,int rit)
{
if(lft<=l[p]&&r[p]<=rit) return sum[p];
if(add[p]>0) pushdown(p);
int ans=0;
if(lft<=r[p <<1]) ans=query(p <<1,lft,rit);
if(l[p <<1|1]<=rit) ans+=query(p <<1|1,lft,rit);
return ans;
}
int LCAu(int x)
{
int ans=0,tot=0;
while(top[x]!=0)
{
tot+=dfn[x]-dfn[top[x]]+1,ans+=query(1,dfn[top[x]],dfn[x]);
update(1,dfn[top[x]],dfn[x],1);
x=fa[top[x]];
}
tot+=dfn[x]-dfn[top[x]]+1,ans+=query(1,dfn[top[x]],dfn[x]);
update(1,dfn[top[x]],dfn[x],1);
return tot-ans;
}
int main()
{
n=read();
m=n-1;
for(ri i=1;i<=m;i++)
{
v[i]=i;
u[i]=read();
nxt[i]=fst[u[i]],fst[u[i]]=i;
}
dfs1(0,0,0);
dfs2(0,0);
build(1,1,n);
q=read();
for(ri i=1;i<=q;i++)
{
cin>>ss; num=read();
if(ss=="install") cout<<LCAu(num)<<'\n';
if(ss=="uninstall")
{
cout<<query(1,dfn[num],dfn[num]+siz[num]-1)<<'\n';
update(1,dfn[num],dfn[num]+siz[num]-1,2);
}
}
return 0;
}