链接:http://poj.org/problem?id=3321
来源:POJ
题意:有一颗以1为根的树,每个结点上都有一个苹果。每次有两种操作:
C x x上的苹果状态发生了改变。如果原来有苹果,那么被摘了;否则,现在放上去一个。
Q x 询问以x为根的子树里共有几个苹果。
思路:使用dfs序,一个子树对应一个区间
#include<cstdio>
#include<iostream>
#include<stack>
#include<cstring>
#define LNode x<<1
#define RNode x<<1|1
using namespace std;
typedef long long ll;
const int Max_n=1e5+10;
struct Edge{
int v,next;
Edge(){}
Edge(int v,int next):v(v),next(next){};
}edge[Max_n<<1];
int st[Max_n],ed[Max_n],tot,sum[Max_n<<2],h[Max_n],cnt,n;
void addedge(int u,int v){
edge[cnt]=Edge(v,h[u]);
h[u]=cnt++;
}
void update(int x){
sum[x]=sum[LNode]+sum[RNode];
}
void build(int l,int r,int x){
if(l==r){
sum[x]=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,LNode);
build(mid+1,r,RNode);
update(x);
}
//bfs可以找到相邻结点
void dfs(int u,int fa){//dfs(找到子树代表的区间)
st[u]=++tot;//u在dfs序中的左端点
for(int i=h[u];i!=-1;i=edge[i].next){
if(edge[i].v!=fa) dfs(edge[i].v,u);//不是父亲,dfs孩子
ed[u]=tot;//u在dfs序中的右端点
}
}
//change(st[u],1,n,1)
void change(int pos,int l,int r,int x){
if(l==r){
sum[x]^=1;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) change(pos,l,mid,LNode);
else change(pos,mid+1,r,RNode);
update(x);
}
//query(st[u],ed[u],1,n,1)
//线段树查询(自顶向下)
int query(int A,int B,int l,int r,int x){///区间查询和(log(n)))
if(A<=l&&B>=r) return sum[x];
int mid=(l+r)>>1,ans=0;
if(A<=mid) ans+=query(A,B,l,mid,LNode);//查询左子树
if(B>mid) ans+=query(A,B,mid+1,r,RNode);//查询右子树
return ans;
}
int main(){
scanf("%d",&n);
memset(h,-1,sizeof(h));
int x,y;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
build(1,n,1);
dfs(1,0);
int Q;
char op[2];
scanf("%d",&Q);
while(Q--){
scanf("%s%d",op,&x);
if(op[0]=='Q') printf("%d\n",query(st[x],ed[x],1,n,1));
else change(st[x],1,n,1);
}
return 0;
}