题目
题解:
知识点:
树状数组
分析:
它问的是和,输入的又是树,易想到树状数组
然后呢?
我们可以对它输入的树用单链表表示,在dfs一下,利用时间戳给每个点编号。易得:编号后,一棵子树上的点的编号是连续的区间。这就可以用树状数组维护了,并解决了树状数组的更新了。
然后如何求和?【蓦淂,莞讹锝雏缇菍】我就败在这儿·······
我们要知道子树中的时间戳的最大值才可以。
核心:
void dfs(int u,int fa){
dfn1[u]=++times;
for (int i=h[u];~i;i=ne[i]){
if (e[i]==fa){
continue;
}
dfs(e[i],u);
}
dfn2[u]=times;//最大值
}
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=4e6+5,M=1e6+5;
int n,m;
int e[2*M],ne[2*M],h[M],idx;
int times,dfn1[M],dfn2[M];//dfn编号
bool vis[M];//标记该+1还是-1
int C[N];
inline void init(){
idx=0;
memset(h,-1,sizeof(h));
}
inline void add(int a,int b){
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void dfs(int u,int fa){
dfn1[u]=++times;
for (int i=h[u];~i;i=ne[i]){
if (e[i]==fa){
continue;
}
dfs(e[i],u);
}
dfn2[u]=times;
}
inline int lowbit(int x){
return x&-x;
}
int getsum(int x){
int res=0;
for (int i=x;i>0;i-=lowbit(i)){
res+=C[i];
}
return res;
}
void update(int x,int v){
for (int i=x;i<=n;i+=lowbit(i)){
C[i]+=v;
}
}
int main(){
init();
scanf("%d%d",&n,&m);
for (int i=0;i<n-1;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
update(i+1,1);
}
update(n,1);
dfs(1,-1);
while (m--){
char c;
int x;
scanf(" %c%d",&c,&x);
if (c=='C'){
update(dfn1[x],vis[x]==true ? 1 : -1);
vis[x]^=1;
}else{
printf("%d\n",getsum(dfn2[x])-getsum(dfn1[x]-1));
}
}
return 0;
}