poj 3321

来源:互联网 发布:淘宝互动平台在哪看 编辑:程序博客网 时间:2024/05/01 03:46

给出一棵树,判断 以 某个 节点 为 根 的子树 有多少个节点有苹果。。

知道要用树状数组求和,但是 每个子树节点编号不连续,头疼,后来看了一些大神的报告才 恍然大悟。

可以先进行一次 dfs 后序遍历,对 每个节点重新编号,使子树的每个节点编号连续,并且根节点编号最大,同时要记录每棵子树的范围

即 子树 的最大编号和最小编号,然后 树状数组。。

ps:建树也不太会。。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 100005struct Edge{int v,next;//v记录边头部,next记录下一边}edge[MAXN];struct Range{//存每个子树范围int low,high;}range[MAXN];int root[MAXN];// root[u]以u为根的节点编号int c[MAXN];int app[MAXN];//the state of pointint index,n,m;inline void addEdge(int u,int v){//加边,将节点插入头部edge[index].v=v;edge[index].next=root[u];root[u]=index++;}inline void dfs(int u){//后序遍历range[u].low=index;//记录最小编号if(root[u]==-1){range[u].high=index++;return;}else {for(int i=root[u];i!=-1;i=edge[i].next){dfs(edge[i].v);}}range[u].high=index++;//记录最大编号,即根的编号}inline int lowbit(int x){return x&(-x);}inline void update(int i,int v){while(i<=n){c[i]+=v;i+=lowbit(i);}}inline int getsum(int i){int sum=0;while(i>0){sum+=c[i];i-=lowbit(i);}return sum;}int main(){int i,j;int u,v;char cmd;while(scanf("%d",&n)==1){memset(root,-1,sizeof(root));index=1;for(i=1;i<n;i++){scanf("%d%d",&u,&v);addEdge(u,v);}fill(app,app+n+5,1);for(i=1;i<=n;i++)c[i]=lowbit(i);//初始化,一开始每个节点都有 appleindex=1;dfs(1);scanf("%d",&m);while(m--){scanf(" %c%d",&cmd,&u);if(cmd=='C'){int val=1;if(app[u])val=-1;app[u]=!app[u];update(range[u].high,val);}else {int val=getsum(range[u].high)-getsum(range[u].low-1);printf("%d\n",val);}}}return 0;}/*101 5 33 21 35 710 910 85 105 6100Q 110Q 21C 10Q 19Q 102C 10Q 103*/