hdu3887

/*
分析:
    ╮(╯▽╰)╭,昨天晚上见到了这个题,今天上午两节
课,一下课就到实验室刷这个题,愣是WA+OLT了俩小时。最
后无比郁闷的去上下午的两节课了,有一节还是体育、中午
还牟吃饭T^T,晚上的课直接翘掉,终于搞定这个题了。
    树状数组很早就会了,你说我得有多菜,囧~~~
    还意外的上了第一版,囧~,虽然倒数第二吧,囧~


    思路:
        10W的数据,杭电OJ用DFS的话必须会爆,所以就自
    己手动模拟栈吧(人才培养方案关于程序的只有一门C的、
    数据结构都要自己学的人儿,桑不起呀囧~)。
        然后DFS的过程中,每个节点都会有两次作为当前节
    点的时候,仔细想想,这两次之间的过程所扫描到的点,
    必定都是其子孙节点。那么,记录第一、二次扫描到这
    个节点的时候,树状数组C中,在其前面并且比它小的点
    的数量,则:ans[i]=num2[i]-num1[i]。
        而树状数组,在每一个节点要退出栈的时候,以这
    个元素更新一次(注意,如果让树状数组C[i]表示“<=”i
    的元素个数的话,那么要先得到num2[i],然后再更新,
    否则会计算自己的)。


    PS:暂时不会神马Cplusplus的容器,所以用的静态临街
    表。我做了一个小优化,用eage_now[节点[i]]来记录当
    前该扫描节点[i]的哪一条边了,省的重复调用前面已经
    搜索过的边。弱菜很囧~~~


                                          2012-10-16
*/










#include"stdio.h"
#include"string.h"
#include"stdlib.h"
int n,root;
int C[100011];
int ans[100011];
int hash[100011];
int queue[100011];
int eage_now[100011];
struct Eage
{
	int from,to,next;
}eage[200011];
int tot,head[100011];
void add(int a,int b)
{
	eage[tot].from=a;
	eage[tot].to=b;
	eage[tot].next=head[a];
	head[a]=tot++;
}
int query(int k)
{
	int t=0;
	while(k>0)
	{
		t+=C[k];
		k-=k&(-k);
	}
	return t;
}
void update(int k,int dir)
{
	while(k<=n && k>0)
	{
		C[k]+=dir;
		k+=k&(-k);
	}
}
void DFS()
{
	int z,i,j;
	int k=0;
	int flag;

	memset(hash,0,sizeof(hash));
	hash[root]=1;
	queue[++k]=root;
	ans[root]=0;
	for(i=0;i<=n;i++)	eage_now[i]=head[i];
	while(k)
	{
		flag=0;
		for(j=eage_now[queue[k]];j!=-1;j=eage[j].next)
		{
			z=eage[j].to;
			if(hash[z])	continue;
			eage_now[queue[k]]=eage[j].next;
			queue[++k]=z;
			hash[z]=1;
			ans[z]=query(z);
			flag=1;
			break;
		}
		if(flag==0)
		{
			ans[queue[k]]=query(queue[k])-ans[queue[k]];
			update(queue[k],1);
			k--;
		}
	}
}
int main()
{
	int i;
	int a,b;
	while(scanf("%d%d",&n,&root),n||root)
	{
		tot=0;
		memset(head,-1,sizeof(head));
		for(i=1;i<n;i++)	{scanf("%d%d",&a,&b);add(a,b);add(b,a);}

		memset(C,0,sizeof(C));
		DFS();

		for(i=1;i<n;i++)	printf("%d ",ans[i]);
		printf("%d\n",ans[n]);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值