题目大意:有一颗长满苹果的苹果树,有两个操作。
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 ",(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; }