题目链接:传送门
题意:
给定一颗树,初始的时候每个节点的值为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; }