题目:http://poj.org/problem?id=3321
这题的难点不在于树状数组,而是如果将整棵树映射到数组中。我们可以用DFS()改时间戳的方法,用begin[i]表示以i为根的子树遍历的第一个点,end[i]表示以i为根的子树遍历的最后一个点。比如数据为:
5
1 2
2 5
2 4
1 3
那么begin[] = {1, 2, 5, 4, 3}, end[] = {5, 4, 5, 4, 3},下标从1开始。
对于每个点都对应一个区间(begin[i], end[i]),如果要改变点a的状态,只要Update(begin[a]),要求该子树的苹果树,即Getsum(begin[a] ) - Getsum(end[a] + 1),(注:这里求和是求x递增的路径的和。)
我做的时候老是超时,把vector<int > v[maxn] , 改成 typedef vector<int > INT; vector<INT> v(maxn); 就过了。。= =!
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 100010;
int cnt,s[maxn],e[maxn],c[maxn];
bool vis[maxn],apple[maxn];
typedef vector<int > INT;
vector<INT > v(maxn);
int n;
void dfs(int cur){
s[cur]=++cnt; vis[cur]=true;
for(int i=0;i<v[cur].size();i++){
int u =v[cur][i];
if(!vis[u])
dfs(u);
}
e[cur]=cnt;
return ;
}
inline int lowbit(int x){ return x&-x; }
int sum(int x){
int ret=0;
while(x>0){
ret+=c[x]; x-=lowbit(x);
}
return ret;
}
void update(int x){
int d;
if(apple[x]==true){
apple[x]=false;
d=-1;
}
else{
apple[x]=true;;
d=1;
}
while(x<=n){
c[x]+=d; x+=lowbit(x);
}
}
int main(){
int m,a,b; char op[10];
memset(vis,false,sizeof(vis));
memset(c,0,sizeof(c));
scanf("%d",&n);
for(int i=0;i<n-1;i++){
scanf("%d %d",&a,&b);
v[b].push_back(a);
v[a].push_back(b);
}
cnt=0; dfs(1);
scanf("%d",&m);
for(int i=1;i<=n;i++){
update(i);
apple[i]=true;
}
while(m--){
scanf("%s",op);
if(op[0]=='Q'){
scanf("%d",&a);
printf("%d\n",sum(e[a])-sum(s[a]-1));
}
else{
scanf("%d",&a);
update(s[a]);
}
}
return 0;
}