hdu3887求一棵树中每个结点的子树中比其序号小的数目

来源:互联网 发布:自考和网络教育哪个好 编辑:程序博客网 时间:2024/04/28 19:27
//求树中每个结点的子树中比本身序号小的结点数目。深搜过程中,会进入每个结点,也会退出每个结点//而两次比其序号小的结点数目之差就是其子树中比其序号小的结点数目。点数多,用栈模拟#include<stdio.h>#include<iostream>#include<vector>#include<string.h>using namespace std;const int maxn=110000;vector<int> e[maxn];int n,p,q[maxn],T[maxn],num[maxn],pt[maxn];bool flag[maxn];int Lowbit(int t){return t&(t^(t-1));}void query(int t){int i=t;while(t>=1){num[i]+=T[t];t-=Lowbit(t);}}void Add(int t,int x){while(t<=n){T[t]+=x;t+=Lowbit(t);}}void DFS()//用栈模拟程序{int top=0,i,j,k;memset(num,0,sizeof(num));memset(flag,false,sizeof(flag));memset(T,0,sizeof(T));pt[p]=p;q[top++]=p;while(top){k=q[top-1];if(flag[k]){top--;i=num[k];//前面一次比它小的num[k]=0;query(k);//现在比它小的num[k]-=i;//结果}else{Add(k,1);//将此结点加入树状数组num[k]=0;query(k);//将进入深插时小于其序号的结点数目存入num[k]中flag[k]=true;//标记它的子代全部for(i=0;i<e[k].size();i++){j=e[k][i];if(j==pt[k]) continue;//父结点pt[j]=k;q[top++]=j;}}}}int main(){int i,j,u,v;while(scanf("%d%d",&n,&p)!=EOF){if(!n&&!p) break;for(i=1;i<=n;i++)//记得清空e[i].clear();for(i=1;i<n;i++){scanf("%d%d",&u,&v);e[u].push_back(v);e[v].push_back(u);}DFS();for(i=1;i<n;i++)printf("%d ",num[i]);printf("%d\n",num[n]);}return 0;}