题目大意
有一颗苹果树,它有N个树叉,每个树叉最开始的时候都结了一个苹果,有时卡卡会从树上把某个苹果摘下来,有时没结苹果的树叉上又会长出苹果来,卡卡有时还想知道某个子树的总苹果数量有多少
题解
题目也是要求实现单点加减,区间求和的功能,赤裸裸的树状数组呀,不过此题给出的不是一个线性的序列,而是树形的,因此我们需要先进行预处理,把树转换为线性序列。用邻接表建立好树,然后对树进行重新编号,这个可以用DFS来实现,每个节点记录第一次访问和最后一次访问时的编号,假设为l和r,那么区间[l,r]之间的所有编号是以此节点为根节点的子树的各个节点的编号,这样就把树转化为线性结构了,之后就是用树状数组来处理了
代码:
#include<iostream> #include<cstdio> #include<cstring> #define MAXN 100005 using namespace std; typedef struct { int adv; int next; } NODE; NODE edg[2*MAXN]; int head[MAXN],c[MAXN],low[MAXN],high[MAXN]; bool visit[MAXN]; int n,m,k,step=0; int lowbit(int x) { return x&-x; } int sum(int x) { int ret=0; while(x>0) { ret+=c[x]; x-=lowbit(x); } return ret; } void add(int x,int d) { while(x<=n) { c[x]+=d; x+=lowbit(x); } } void addege(int u,int v) { edg[k].adv=v; edg[k].next=head[u]; head[u]=k++; } void dfs(int u) { int i; low[u]=++step; visit[u]=true; for(i=head[u]; i!=-1; i=edg[i].next) if(!visit[edg[i].adv]) dfs(edg[i].adv); high[u]=step; } int main(void) { int i,u,v; bool f[MAXN]; char ch; memset(head,-1,sizeof(head)); memset(visit,false,sizeof(visit)); memset(f,false,sizeof(f)); scanf("%d",&n); k=1; for(i=1; i<n; i++) { scanf("%d%d",&u,&v); addege(u,v); add(i,1); } add(i,1); dfs(1); scanf("%d",&m); while(m--) { getchar(); scanf("%c%d",&ch,&i); if(ch=='C') { if(!f[i]) { add(low[i],-1); f[i]=true; } else { add(low[i],1); f[i]=false; } } else printf("%d\n",sum(high[i])-sum(low[i]-1)); } return 0; }