题意:一棵具有n个节点的树,一开始,每个节点上都有一个苹果。现在给出m组动态的操作:(C,i)是摘掉第i个节点上面的苹果(若苹果不存在,则为加上一个苹果),(Q,i)是查询以第i个节点为根的子树有几个苹果(包括第i个节点)。
思路:树状数组。这道题重点怎么建立树到树状数组的映射关系:利用dfs遍历树,对每个节点进行两次编号,第一次搜到第i个节点时的深度dep,为这个节点管辖区间的上限low[i](也为这个节点的下标),然后搜这个节点的子节点,最后搜回来后的深度dep,为这个节点管辖区间的下限high[i],如下图所示。接下来就是树状数组部分了。
代码:
#include<iostream>
#include<fstream>
using namespace std;
int n,m;
struct e{
int data;
e *next;
};
e edge[100001];
int node[100001];
int v[100001];
int b[100001];
int end[100001];
int sum;
void dfs(int s){
int i,j,k;
v[s]=++sum;
e *p=edge[s].next;
while(p){
if(v[p->data]==0)
dfs(p->data);
p=p->next;
}
end[s]=sum;
}
int lowbit(int x){
return x&(-x);
}
void add(int s,int t){
while(s<=n)
{
b[s]+=t;
s+=lowbit(s);
}
}
int getsum(int s){
int i=0;
while(s>0)
{
i+=b[s];
s-=lowbit(s);
}
return i;
}
void read(){
// ifstream cin("in.txt");
int i,j,k,s,t;
// cin>>n;
scanf("%d",&n);
for(i=1;i<n;i++)
{
// cin>>s>>t;
scanf("%d%d",&s,&t);
e *p=new e;
p->data=t;
p->next=edge[s].next;
edge[s].next=p;
e *q=new e;
q->data=s;
q->next=edge[t].next;
edge[t].next=q;
}
dfs(1);
char c;
for(i=1;i<=n;i++)
add(i,1);
// cin>>m;
scanf("%d",&m);
for(i=1;i<=m;i++)
{
// cin>>c>>j;
getchar();
scanf("%c%d",&c,&j);
if(c=='C')
{
s=getsum(v[j]);
s-=getsum(v[j]-1);
if(s==1)
add(v[j],-1);
else
add(v[j],1);
}
else
{
s=getsum(end[j]);
s-=getsum(v[j]-1);
cout<<s<<endl;
}
}
}
int main(){
read();
return 0;
}