有n个节点以1为根节点的树,给你树的边关系u-v,一开始每个节点都有一个苹果,接下来有两种操作,C x改变节点x的苹果状态,Q x查询x为根的树的所有苹果个数。
求出树的dfs序,st[i]保存i的进入时间戳,ed[i]保存i的退出时间戳,则st[i]到ed[i]就是子树节点的对应时间戳。
每个节点打了两次时间戳,其中ed[i]会等于最后访问的一个子节点的st[i]。
于是用线段树/树状数组的单点修改和区间求和就可以解决。
#include<cstdio> #define N 100005 using namespace std; int n,m,id,cnt; int q[N],st[N],ed[N],head[N]; int rl[N<<2],rr[N<<2],sum[N<<2]; struct edge{ int to,next; }e[N<<1]; void add(int u,int v){ e[++cnt]=(edge){v,head[u]}; head[u]=cnt; } void dfs(int x,int fa){ st[x]=++id; for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa) dfs(e[i].to,x); ed[x]=id; } void build(int k,int l,int r){ rl[k]=l;rr[k]=r; if(l==r){ sum[k]=1; return; } int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); sum[k]=sum[k<<1]+sum[k<<1|1]; } int query(int k,int a,int b){ int l=rl[k],r=rr[k]; if(a<=l&&r<=b) return sum[k]; if(b<l||a>r)return 0; return query(k<<1,a,b)+query(k<<1|1,a,b); } void modify(int k,int x){ int l=rl[k],r=rr[k],mid=(l+r)>>1; if(l==r){ sum[k]^=1; return; } if(x<=mid)modify(k<<1,x); else modify(k<<1|1,x); sum[k]=sum[k<<1]+sum[k<<1|1]; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1,0); scanf("%d",&m); build(1,1,n); for(int i=1;i<=m;i++){ char op; scanf(" %c",&op); int x; scanf("%d",&x); if(op=='Q') printf("%d ",query(1,st[x],ed[x])); else modify(1,st[x]); } return 0; }
树状数组
#include<cstdio> #define N 100005 using namespace std; int n,m,id,cnt; int q[N],st[N],ed[N],head[N]; int cal[N],a[N]; struct edge{ int to,next; }e[N<<1]; void add(int u,int v){ e[++cnt]=(edge){v,head[u]}; head[u]=cnt; } void dfs(int x,int fa){ st[x]=++id; for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa) dfs(e[i].to,x); ed[x]=id; } int getsum(int x){ int s=0; for(;x;x-=x&(-x))s+=cal[x]; return s; } void update(int v,int x){ for(;x<=n;x+=x&(-x))cal[x]+=v; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v);add(v,u); } dfs(1,0); scanf("%d",&m); for(int i=1;i<=n;i++)update(1,i); for(int i=1;i<=m;i++){ char op; scanf(" %c",&op); int x; scanf("%d",&x); if(op=='C'){ update(a[x]?1:-1,st[x]); a[x]^=1; } else printf("%d ",getsum(ed[x])-getsum(st[x]-1)); } return 0; }