#include<bits/stdc++.h>
using namespace std;
int tr[10003],in[10003],ou[10003],fo[10003];
vector<int>edge[10003];
int n,m,key;
//修改节点k,添加代入1,删除代入-1
void add(int x,int val){
while(x<=n){
tr[x]+=val;
x+=x&(-x);
}
}
//得到1...x的和
int query(int x){
int rec=0;
while(x>0){
rec+=tr[x];
x-=x&(-x);
}
return rec;
}
//为每一个node添加一个左值和右值
void dfs(int node){
in[node]=key;
for(int i=0;i<edge[node].size();i++){
key++;
dfs(edge[node][i]);
}
ou[node]=key;
}
int main(){
while(~scanf("%d",&n)){
int a,b;char ch;
for(int i=1;i<n;i++){
cin>>a>>b;
edge[a].push_back(b);
}
key=1;
dfs(1);
//为每一个节点对应一个左边界和右边界
//他自己就存放在左边界里面
//而它的管辖范围就是左边界到右边界
for(int i=1;i<=n;i++){
fo[i]=1;//最初每个Fork上都有一个苹果
add(i,1);//同时更新树状数组的值
}
cin>>m;
for(int i=0;i<m;i++){
cin>>ch>>b;
if(ch=='Q'){//b子树就是[Left[b],right[b]]
int tmp=query(ou[b])-query(in[b]-1);
cout<<tmp<<endl;
}
else{//每个节点编号就是它左值
if(fo[b])add(in[b],-1);
else add(in[b],1);
fo[b]=!fo[b];//变为相反的状态
}
}
}
return 0;
}
Sample Input Sample Output
3
1 2
1 3
3
Q 1 3
C 2
Q 1 2
DFS序+树状数组POJ3321 Apple Tree
题意:一颗树最初每个节点上都有一个苹果,有两种操作:修改(修改某一个节点,修改时这一个节点苹果从有到无,或从无到有)和查询(查询某一个节点他的子树上有多少个苹果)。由于此题数据比较大(N<=10^5),而且不是标准的二叉树,所以这里我们队每一个节点重新编号,另外为每一个节点赋一个左值和一个右值,表示这个节点的管辖范围。
上图也就是DFS搜索的时候做标记的过程,这样新的编号为1~6的节点所管辖的范围分别就是[1,6] [2,4] [3,3] [4,4] [5,6] [6,6],其中左边的是左值,右边的是右值,节点1的区间是[1,6],正好这棵子树有6个节点,其他也一样。新的节点放进树状数组,求出每一个节点从1~左值-1的和和1~右值的和,他们的差就是这个节点的子树的所有的和(即这棵子树苹果数目)