本题难在转化上面,我们可以想到用树状数组来做。
如右图所示,我们要查询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;
}