对树进行DFS,记时间节点cnt初始等于0,每到一个新的节点(之前没有到过的节点),将cnt+1,作为这个节点的开始时刻,等到遍历完以这个节点为根的子树,回到这个节点时,此时的cnt是这个节点的结束时刻,例如下图:
这样就实现了,将节点与节点之间的包含关系,转化到了线段区间上
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define lowbit(x) (x&(-x))
const int MAXN=1e5+10;
int n,u,v,m,cnt,ecnt;
int tree[MAXN];
int s[MAXN],e[MAXN],vis[MAXN],ismark[MAXN],edge[MAXN<<1],head[MAXN],nxt[MAXN<<1];
inline void rebuild(int x)
{
s[x]=++cnt;
for(int i=head[x];i!=0;i=nxt[i]){
int child=edge[i];
if(ismark[child]==0)
{
ismark[child]=1;
rebuild(child);
}
}
e[x]=cnt;
}
void update(int x,int d)
{
while(x<=cnt)
{
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
while(x>0)
{
ans+=tree[x];
x-=lowbit(x);
}
return ans;
}
inline void add(int u,int v){
edge[++ecnt]=v;
nxt[ecnt]=head[u];
head[u]=ecnt;
}
int main()
{
//freopen("D:\\in.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
ismark[1]=1;
rebuild(1);
for(int i=1;i<=n;i++)
{
update(s[i],1);
}
cin>>m;
char op;
int x;
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++)
{
scanf(" %c%d",&op,&x);
if(op=='Q')
{
printf("%d\n",sum(e[x])-sum(s[x]-1));
}
else
{
if(!vis[x])
{
update(s[x],-1);
vis[x]=1;
}
else
{
update(s[x],1);
vis[x]=0;
}
}
}
return 0;
}