改变某点值,计算和很像树状数组
很难想到的是如何把它变为区间
具体做法是做一次dfs,记下每个节点的开始时间Start[i]和结束时间End[i],
那么对于i节点的所有子孙的开始时间和结束时间都应位于Start[i]和End[i]之间
然后用树状数组C统计Start[i]到End[i]之间的附加苹果总数。
这里用树状数组统计区间可以用Sum(End[i])-Sum(Start[i]-1)来计算。
所以每次更新值都要更新Start[i]和End[i]点,求和的时候也要除以二
另外一个注意事项是一定要用vector<vector<int> > G(maxn) 而不是vector<int> G[maxn] 前者快并且AC了,而后者超时
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100000+5;
vector<vector<int> > G(maxn);
int start[maxn],end[maxn],nNode;
bool haveApple[maxn];
int lowbit[maxn*2];
int C[maxn*2];
void dfs(int u)
{start[u]=++nNode;for(int i=0;i<G[u].size();i++) dfs(G[u][i]);end[u]=++nNode;
}
void Modify(int p,int val)
{while(p<=nNode){C[p]+=val;p+=lowbit[p];}
}
int QuarySum(int p)
{int sum=0;while(p>0){sum+=C[p];p-=lowbit[p];}return sum;
}
int main()
{int N,M;cin>>N;int u,v;for(int i=1;i<=N-1;i++){scanf("%d%d",&u,&v);G[u].push_back(v);}dfs(1);for(int i=1;i<=nNode;i++) {lowbit[i]=i&(-i);C[i]=i-(i-lowbit[i]);}char cmd[5];cin>>M;for(int i=0;i<M;i++){scanf("%s%d",cmd,&u);if(cmd[0]=='C'){if(!haveApple[u]) {Modify(start[u],-1);Modify(end[u],-1);haveApple[u]=true;}else {Modify(start[u],1);Modify(end[u],1);haveApple[u]=false;}}else {int t1=QuarySum(start[u]-1);int t2=QuarySum(end[u]);printf("%d\n",(t2-t1)/2);}}return 0;
}