题目链接
题意:就是给你一个树,每次动态修改一个节点的值,然后问你某一颗子树的节点值的和。
做法:很明显每次修改然后dfs一次是会超时的,所以先跑一遍dfs,给树映射到区间,然后树状数组求和,dfs序,就是每次记录访问到这个节点的时间戳以及访问其儿子节点结束后返回该点的结束时间戳,那么他的儿子节点就是在这2个时间戳之间了,就把树转换为区间了,剩下的就好办了。vector会TLE,所以使用结构存储边。
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define LL long long
#define cl(a,b) memset(a,b,sizeof(a))
const int maxn=100005;
const LL inf=1LL<<32;
double pi=acos(-1.0);
#define gcd __gcd
#define LCM(a,b) (a)*(b)/gcd(a,b)
#define X first
#define Y second
#define pb push_back
#define lowbit(s) (s&(-s))
int cnt,tot;
struct Edge{
int to,next;
}edge[maxn];
int head[maxn];
void addedge(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
int st[maxn],en[maxn];
void dfs(int u){
st[u]=++cnt;
for(int i=head[u];~i;i=edge[i].next)dfs(edge[i].to);
en[u]=cnt;
}
int c[maxn];
void update(int x,int val){
for(int i=x;i<maxn;i+=lowbit(i)){
c[i]+=val;
}
}
int sum(int x){
int ret=0;
for(int i=x;i;i-=lowbit(i))ret+=c[i];
return ret;
}
int h[maxn];
int main(){
cl(head,-1);
int n;scanf("%d",&n);
for(int i=0;i<n-1;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
}
dfs(1);int q;
for(int i=1;i<=n;i++){
update(st[i],1);h[i]=1;
}
char op[3];
scanf("%d",&q);
while(q--){
int num;
scanf("%s%d",op,&num);
if(op[0]=='Q'){
printf("%d\n",sum(en[num])-sum(st[num]-1));
}
else {
if(h[num]){
update(st[num],-1);
}
else {
update(st[num],1);
}
h[num]=!h[num];
}
}
return 0;
}