一棵树,开始时每个结点都有一个苹果,输入C x表示更新x结点,若x结点有苹果,把该结点苹果摘掉,若该节点无苹果,在该节点上增加一个新的苹果。输入Q x表示以该节点为根的子树有多少个苹果。伸手便
该题主要问题是如何把一棵树转化为树状数组,之后便可以直接运用树状数组来求区间的和。转化的方法是用dfs深搜遍历树,每一个结点要做两次标记,第一次访问到时标记该结点,即为该结点在树状数组中的起始位置,第二次当dfs深搜返回时又一次标记,即为该结点在树状数组中末位置,始末位置之间即代表了以该结点为根的子树的所有结点。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
const int MAX = 100005;
struct{
int v, nxt;
}edge[2*MAX];
int k = 1, edgeHead[MAX];
int n, m, dep, c[MAX];
int low[MAX], high[MAX];
bool pick[MAX], vis[MAX];
void dfs(int u){
low[u] = ++ dep; // 第一次搜到第u个节点时的深度dep,为这个节点管辖区间的上限low[i]。
vis[u] = true;
for(int i = edgeHead[u]; i; i = edge[i].nxt)
if(!vis[edge[i].v])
dfs(edge[i].v);
high[u] = dep; // 最后搜回来后的深度dep,为这个节点管辖区间的下限high[i]。
}
int lowbit(int x){
return x & (-x);
}
void add(int i, int w){
while(i <= n){
c[i] += w;
i += lowbit(i);
}
}
int sum(int i){
int ans = 0;
while(i > 0){
ans += c[i];
i -= lowbit(i);
}
return ans;
}
int main(){
int i, u, v, ans;
scanf("%d", &n);
for(i = 1; i < n; i ++){
scanf("%d%d", &u, &v);
edge[k].v = v;
edge[k].nxt = edgeHead[u];
edgeHead[u] = k ++;
}
for(i = 1; i <= n; i ++)
add(i, 1);
dep = 0;
dfs(1);
scanf("%d", &m);
while(m --){
char ord;
getchar();
ord=getchar();
scanf("%d",&u);
if(ord == 'C'){
if(pick[u]){
add(low[u], 1);
pick[u] = false;
}else{
add(low[u], -1);
pick[u] = true;
}
}else{
ans = sum(high[u]) - sum(low[u]-1);
printf("%d\n", ans);
}
}
system("pause");
return 0;
}