题意:给定一棵树,某些节点上有苹果,多次询问各子树上的节点数,并且在询问的中途随时可能新增和删除苹果。
分析:dfs遍历树的同时,对每个点标注时间,每个点有一个开始时间和一个结束时间,把这两个时间当做下标,该点的苹果个数(1或0)填入数组的两个对应位。子树中结点的时间段一定是根节点时间段的子段,所以求子树苹果数,只需求数组某区间的和即可。用树状数组比较快。
#include<cstdio>
#include<cstring>
const int n_max=200005;
int n,a[n_max],ne,N;
int head[n_max],cnt;
int apple[n_max],pos[n_max];
struct Node
{
int v,last;
}e[n_max];
struct Root
{
int begin,end;
}p[n_max];
void addedge(int x,int y)
{
e[ne].v=y;
e[ne].last=head[x];
head[x]=ne;
ne++;
}
void bfs(int num)
{
p[num].begin=cnt;
int i;
for(i=head[num];i!=-1;i=e[i].last)
{
bfs(e[i].v);
}
pos[num]=cnt;
p[num].end=cnt++;
}
void insert(int k,int p)
{
while(k<=N)
{
a[k]+=p;
k+=k&(-k);
}
}
int sum(int k)
{
int ret=0;
while(k>0)
{
ret+=a[k];
k-=k&(-k);
}
return ret;
}
int main()
{
while(~scanf("%d",&n))
{
ne=0;
memset(head,-1,sizeof(head));
int i,x,y;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
addedge(x,y);
}
cnt=2;
N=n+1;
bfs(1);
for(i=1;i<=n;i++)
{
apple[i]=1;
insert(pos[i],1);
}
int m,t;
char op[10];
scanf("%d",&m);
while(m--)
{
scanf("%s%d",op,&t);
if(op[0]=='Q')
{
printf("%d\n",sum(p[t].end)-sum(p[t].begin-1));
}
else
{
int temp;
if(apple[t]==1)
{
temp=-1;
}
else
{
temp=1;
}
insert(pos[t],temp);
apple[t]+=temp;
}
}
}
return 0;
}