题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=231
解题思路:苹果完全可以倒过来看做一棵树(注意不一定是二叉树),求一个分叉上面的苹果数量,就是求颗子树有多少 节点,对于一个树进行一次遍历后,所有节点都已经访问过了,将遍历序列使用树状数组记录下来的,只需一个 start数组和end数组记录每个子树的开始和结束在序列中的位置,就可以快速的得到子树的节点数量。
本题只需对数进行先根遍历,记录树状数组和开始结束位置,再使用一个has数组对每一个节点标记是否有苹 果。对于每次改变状态,使用树状数组的modify函数对所有涉及到的位置进行改变即可。
代码附上:
#include<stdio.h>
#include<vector>
#include<string.h>
using namespace std;
int nCount = 0;
vector<int> G[100005];
int C[100005], has[100005];
int Start[100005], End[100005];
void DFS(int x) {
Start[x] = ++nCount; //标记开始位置
for(int i = 0; i < G[x].size(); i++) {
DFS(G[x][i]); //标记结束位置
}
End[x] = nCount;
}
int lowbit(int x) {
return x&(-x);
}
int Sum(int x) {
int nSum = 0;
while(x > 0) {
nSum += C[x];
x -= lowbit(x);
}
return nSum;
}
void Modify(int x, int val) {
while(x <= nCount) {
C[x] += val;
x += lowbit(x);
}
}
int main() {
// freopen("data.in", "r", stdin);
int n, m;
int a,b;
scanf("%d", &n);
for(int i = 1;i < n; i++) {
scanf("%d%d", &a, &b);
G[a].push_back(b);
}
nCount = 0; DFS(1);
//每个节点一个苹果,树状数组数值即lowbit
for(int i = 1; i <= nCount; i++) {
C[i] = lowbit(i);
}
memset(has, 1, sizeof(has));
scanf("%d", &m);
for(int i = 0;i < m; i++) {
char cmd[5];
scanf("%s%d", cmd, &a);
if(cmd[0] == 'C') {
if(has[a]) { //如果等于说明该节点有苹果,应该摘取
has[a] = 0;
Modify(Start[a], -1);
} else {
has[a] = 1;
Modify(Start[a], 1);
}
} else {
printf("%d\n",Sum(End[a]) - Sum(Start[a]-1));
}
}
return 0;
}