题目大意:有一颗长满苹果的苹果树,有两个操作。
1.询问以一个点为根的子树中有多少个苹果。
2.看看一个点有没有苹果,假设没有苹果。那么那里就立即长出一个苹果(= =!);否则就把那个苹果摘下来。
思路:进行一次深搜,将每一个节点最開始出现的时间和最后出现的时间记在一个数组里,那么这两点之间的点就是它以及它的子树的二倍,然后就用树状数组来维护区间和即可了。
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 200010
using namespace std; pair<int,int> pos[MAX]; int points,asks;
int head[MAX],total;
int next[MAX << 1],aim[MAX << 1];
int cnt;
bool src[MAX];
int fenwick[MAX]; char c[10]; inline void Add(int x,int y);
void DFS(int x,int last); inline void Fix(int x,int c);
inline int GetSum(int x); int main()
{
cin >> points;
for(int x,y,i = 1;i < points; ++i) {
scanf("%d%d",&x,&y);
Add(x,y),Add(y,x);
}
DFS(1,-1);
memset(src,true,sizeof(src));
for(int i = 1;i <= points; ++i)
Fix(pos[i].first,1),Fix(pos[i].second,1);
cin >> asks;
for(int x,i = 1;i <= asks; ++i) {
scanf("%s%d",c,&x);
if(c[0] == 'Q')
printf("%d\n",(GetSum(pos[x].second) - GetSum(pos[x].first - 1)) >> 1);
else {
if(src[x]) {
Fix(pos[x].first,-1);
Fix(pos[x].second,-1);
src[x] = false;
}
else {
Fix(pos[x].first,1);
Fix(pos[x].second,1);
src[x] = true;
}
}
}
return 0;
} inline void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
} void DFS(int x,int last)
{
pos[x].first = ++cnt;
for(int i = head[x];i;i = next[i]) {
if(aim[i] == last) continue;
DFS(aim[i],x);
}
pos[x].second = ++cnt;
} inline void Fix(int x,int c)
{
for(;x <= (points << 1);x += x&-x)
fenwick[x] += c;
} inline int GetSum(int x)
{
int re = 0;
for(;x;x -= x&-x)
re += fenwick[x];
return re;
}