本題難在轉化上面,我們可以想到用樹狀數組來做。
如右圖所示,我們要查詢2
點的時候,他的孩子爲 4 和 5 ,但是這 3 個點並不是連續的,就不能用樹狀數組來做。
所以問題的關鍵就在於,如何把一個點和它的孩子節點連續起來。
用 dfs 遞歸一個點的時候,把所有能和它相連 的點都訪問一邊,然後對應邊上序號。就和樹狀數組裏面的點對應起來。
在用vector 容器的時候,有一個地方需要注意
vector<int>v[maxn] ; 用起來會超時
typedef vector<int > INT;
vector<INT > v(maxn); 可以AC 。
#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 100010;
int n,cnt,s[maxn],e[maxn],c[maxn];
bool vis[maxn],apple[maxn];
//vector<int>v[maxn];
typedef vector<int > INT;
vector<INT > v(maxn);
void dfs(int cur)//遞歸調用,把能和 cur 相連的點連續起來
{
s[cur] = ++cnt;// s 表示有 cur 開始的起點
vis[cur] = 1;
for(int i = 0; i< v[cur].size(); i++)
{
int u = v[cur][i];
if(!vis[u]) dfs(u);
}
e[cur] = cnt; // e 表示有 cur 開始的終點
return ;
}
int lowbit(int x)
{
return x & (-x);
}
void update(int x)
{
int d ;
if(apple[x])//剛開始的時候所有的點都是有蘋果的,apple 全部都是false,
{
apple[x] = false;
d = -1;
}
else
{
apple[x] = true;
d = 1;
}
while(x <= n)
{
c[x] += d;
x += lowbit(x);
}
}
int getsum(int x)
{
int res = 0;
while(x)
{
res += c[x];
x -= lowbit(x);
}
return res;
}
int main()
{
char ch[2];
while(~scanf("%d",&n))
{
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
int i,a,b,m;
for(i = 1; i < n; i++)
{
scanf("%d%d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
cnt = 0;
dfs(1);
for(i = 1; i <= n; i++)
{
update(i);
apple[i] = i;
}
//cout<<"****"<<endl;
scanf("%d",&m);
for(i = 1; i <= m; i++)
{
scanf("%s%d",&ch,&a);
if(ch[0] == 'Q') printf("%d\n",getsum(e[a]) - getsum(s[a] -1));
else
{
update(s[a]);
}
}
}
return 0;
}