题目链接:http://poj.org/problem?id=3321
题意:有一棵苹果树,最开始长满了苹果。有两种操作,C操作用于修改某个结点,若原来有苹果,则去掉,若原来没苹果,则加上。Q操作询问某个结点及其所有子树总苹果数量。
思路:树状数组的操作,可以从树根开始进行一次DFS,对每个结点进行标号。易知,某个结点及其子树的标号一定是一个连续的区间,这样,记录好每个结点的区间范围,求和时应用树状数组即可。
#include<cstdio>
#include<cstring>
#include<string>
#include<cctype>
#include<iostream>
#include<set>
#include<map>
#include<cmath>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<bitset>
#include<algorithm>
#define fin(a) freopen("a.txt","r",stdin)
#define fout(a) freopen("a.txt","w",stdout)
typedef long long ll;
using namespace std;
const int maxn = 110000 + 10;
vector<vector<int> > G(maxn);
int L[maxn], R[maxn], ID[maxn], C[maxn];
int cnt;
bool have[maxn];
void dfs(int u, int fa) {
ID[u] = ++cnt; L[ID[u]] = cnt;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(v == fa) continue;
dfs(v, u);
}
R[ID[u]] = cnt;
}
int lowbit(int x) {
return x & -x;
}
void add(int x, int v) {
while(x <= cnt) {
C[x] += v;
x += lowbit(x);
}
}
int Sum(int x) {
int ans = 0;
while(x > 0) {
ans += C[x];
x -= lowbit(x);
}
return ans;
}
int main() {
int n, q;
scanf("%d", &n);
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, -1);
memset(have, true, sizeof have);
for(int i = 1; i <= cnt; i++) add(i, 1);
scanf("%d", &q);
while(q--) {
char s[2]; int x;
scanf("%s %d", s, &x);
x = ID[x];
if(s[0] == 'Q') {
int l = L[x], r = R[x];
printf("%d\n", Sum(r) - Sum(l-1));
}
else {
if(have[x]) add(x, -1);
else add(x, 1);
have[x] = !have[x];
}
}
return 0;
}