题目链接:传送门
题意:
给定一颗树,初始的时候每个节点的值为1。
修改操作:C X 如果点X的值为1则变成0,如果点X的值为0则变成1.
查询操作:Q X 查询X这个节点以及以它为根的子树的所有节点的和。
分析:
DFS序:根据dfs的时候节点进栈与出栈的时间点。in[u]/out[u]代表点u进/出栈的时间,那么(in[u],out[u])之间的节点就是点u子树上的节点。
我们根据DFS序来维护一个树状数组就可以了。
代码如下:
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 1e5+10;
int has[maxn];
int n;
struct Tree{
struct nod{
int to,next;
}edge[maxn];
int in[maxn],out[maxn],tt;
int head[maxn],ip;
void init(){
tt=0,ip=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v){
edge[ip].to= v;
edge[ip].next = head[u];
head[u]= ip++;
}
void dfs(int u){
in[u]=++tt;
for(int i=head[u];i!=-1;i=edge[i].next){
int v = edge[i].to;
dfs(v);
}
out[u]=tt;
}
}G;
struct BIT {
int sum[maxn];
void init(){
memset(sum,0,sizeof(sum));
}
int lowbit(int x) {
return x&(-x);
}
void update(int pos,int x){
while(pos<=n){
sum[pos]+=x;
pos+=lowbit(pos);
}
}
int query(int pos){
int ans = 0;
while(pos>0){
ans+=sum[pos];
pos-=lowbit(pos);
}
return ans;
}
}T;
int main() {
while(~scanf("%d",&n)){
G.init();
T.init();
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
G.add(u,v);
}
G.dfs(1);
for(int i=1;i<=n;i++){
T.update(G.in[i],1);
has[i]=1;
}
int x,m;
scanf("%d",&m);
char s[2];
while(m--){
scanf("%s%d",s,&x);
if(s[0]=='C'){
if(has[x])
T.update(G.in[x],-1);
else
T.update(G.in[x],1);
has[x]^=1;
}
else
printf("%d\n",T.query(G.out[x])-T.query(G.in[x]-1));
}
}
return 0;
}