/*
分析:
╮(╯▽╰)╭,昨天晚上见到了这个题,今天上午两节
课,一下课就到实验室刷这个题,愣是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;
}