题意:给出一个多叉树(不一定是二叉),每个树上有一个苹果,有n-1条边,m次操作
操作有两种:
一:每次操作使该节点的苹果从有到无或从无到有,每个节点最多有一个苹果
二:查询该节点的子树上共有多少个苹果
思路:先用dfs序给所有节点标号(相当于映射成线性的),然后用线段树维护,单点更新和区间查询。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <cmath> #include <queue> using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=110000; int n,m,k; int tot; struct Edge{ int to; int next; }edge[maxn*2]; int e,head[maxn]; int in[maxn],out[maxn],vis[maxn]; void init(){ e=0;tot=1; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); } void addEdge(int u,int v){ edge[e].to=v; edge[e].next=head[u]; head[u]=e++; } void dfs(int x){ in[x]=tot++; vis[x]=1; for(int i=head[x];~i;i=edge[i].next){ if(!vis[edge[i].to]) dfs(edge[i].to); } out[x]=tot-1; } struct segTree{ int l; int r; int sum; }node[maxn*4]; void PushUp(int rt){ node[rt].sum=node[rt<<1].sum+node[rt<<1|1].sum; } void build(int rt,int l,int r){ node[rt].l=l; node[rt].r=r; node[rt].sum=r-l+1; if(l==r) return ; int mid=(l+r)>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } void Update(int rt,int l,int r,int pos){ if(l==r){ node[rt].sum^=1; return ; } int mid=(l+r)>>1; if(mid>=pos) Update(rt<<1,l,mid,pos); else Update(rt<<1|1,mid+1,r,pos); PushUp(rt); } int Query(int rt,int l,int r,int L,int R){ if(L<=l&&r<=R) return node[rt].sum; int mid=(l+r)>>1; if(mid>=R) return Query(rt<<1,l,mid,L,R); else if(mid<L) return Query(rt<<1|1,mid+1,r,L,R); else return Query(rt<<1,l,mid,L,mid)+Query(rt<<1|1,mid+1,r,mid+1,R); } int main(){ while(~scanf("%d",&n)){ init(); int u,v; for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); addEdge(u,v); addEdge(v,u); } dfs(1); build(1,1,n); scanf("%d",&m); char ch[3]; while(m--){ scanf("%s%d",ch,&k); if(ch[0]=='C') Update(1,1,n,in[k]); else printf("%d\n",Query(1,1,n,in[k],out[k])); } } return 0; }