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

//求树中每个结点的子树中比本身序号小的结点数目。深搜过程中,会进入每个结点,也会退出每个结点
//而两次比其序号小的结点数目之差就是其子树中比其序号小的结点数目。点数多,用栈模拟
#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;
}

 

你可能感兴趣的:(hdu3887求一棵树中每个结点的子树中比其序号小的数目)