題意:一顆蘋果樹,樹上有n個樹枝節點,一個節點有一個蘋果,有n-1個樹枝。模型是即n個點n-1條邊的樹,叉數不定。對這棵樹可進行兩種操作,其中Q x是詢問第x節點上子樹的蘋果個數,C x是如果x節點上有蘋果,就會被拿掉,如果沒有,樹就會長出蘋果。
思路:本題關鍵就在於建立樹和樹狀數組的映射關係。對於每一個樹枝節點,我們需要知道的就是它的管轄範圍,即它下面包括自己一共管了多少個節點,並且指定到具體區間,那麼首先就需要DFS遍歷這個樹,在DFS內使用一個累加器記錄遍歷節點的個數,在遞推到某個節點的時候累加器的值就是這個節點所管轄範圍的起始值即下限,當又一次回溯回這個節點的時候累加器的值就是這個節點所管轄範圍的上限。這個節點的下限就是這個節點在樹狀數組中的位置,計算query(high)- query(low-1)可得到該節點所有蘋果個數。
下面這個圖有助於理解:
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
struct node
{
int v,next;
}d[1000000];
struct NODE
{
int low,high;
}p[100010];
int head[100010];
int vis[100010];
int atree[100010],a[100010];
int step,n;
void DFS(int u)
{
vis[u]=1;
step++;
p[u].low=step;
for(int i=head[u];i!=-1;i=d[i].next)
{
if(!vis[d[i].v])
{
DFS(d[i].v);
}
}
p[u].high=step;
}
void add(int t,int d)
{
while(t<=n)
{
atree[t] += d;
t+=t&-t;
}
}
int query(int t)
{
int sum=0;
while(t>0)
{
sum += atree[t];
t-=t&-t;
}
return sum;
}
int main()
{
int m,x;
int cnt=0;
int u,v;
char c[2];
step=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(atree,0,sizeof(atree));
scanf("%d",&n);
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&u,&v);
d[cnt].next=head[u];
d[cnt].v=v;
head[u]=cnt++;
d[cnt].next=head[v];
d[cnt].v=u;
head[v]=cnt++;
}
DFS(1);
for(int i=1;i<=n;i++)
{
add(i,1);
a[i]=1;
}
scanf("%d%*c",&m);
while(m--)
{
scanf("%s",c);
if(c[0]=='C')
{
scanf("%d%*c",&x);
if(a[p[x].low]==1){
add(p[x].low,-1);
a[p[x].low]=0;
}
else
{
add(p[x].low,1);
a[p[x].low]=1;
}
}
else
{
scanf("%d%*c",&x);
int ans=query(p[x].high)-query(p[x].low-1);
printf("%d\n",ans);
}
}
return 0;
}