DFS序的意义:对一棵树进行DFS遍历,一个结点最多到达两次,
一次入,一次出,而这之间的结点标号均为它的子树结点的标号。所以只要用某种方法快速查询其左右标号内含的区间中,比它小的标号个数即可
//#pragma comment(linker, "/STACK:1024000000,1024000000") //开大栈 防止dfs爆栈
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int M =1e5+5;
int n,p,num;
vector<int> t[M];
int vis[M],seq[M];//seq 存dfs序
int c[M*2+5],f[M];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int val)
{
while(x<M)
{
c[x]+=val;
x+=lowbit(x);//往右上走
}
}
int sum(int x)
{
int ans=0;
while(x>0)
{
ans+=c[x];
x-=lowbit(x);//往前走
}
return ans;
}
//DFS的遍历的意义。对一棵树进行DFS遍历,一个结点最多到达两次,
//一次入,一次出,而这之间的结点标号均为它的子树结点的标号。所以只要用某种方法快速查询其左右标号内含的区间中,比它小的标号个数即可
void dfs(int rt)
{
int x=sum(rt);//不是它的子树但是比它小的个数
//seq[++num]=rt;//入
vis[rt]=1;
update(rt,1);//
for(int i=0;i<t[rt].size();i++)
{
int son=t[rt][i];
if(!vis[son])
{
dfs(son);
}
}
f[rt]=sum(rt)-x-1;//f[x]=当前(遍历子树后)比它小的总和-x(比它小但不是它的son) -1自己记录了一次
//seq[++num]=rt;//出,出入之间中间节点为它的子树
}
int main()
{
while(cin>>n>>p&&(n||p))
{
for(int i=1;i<=n;i++)
{
t[i].clear();
}
memset(vis,0,sizeof(vis));
memset(c,0,sizeof(c));
for(int i=1;i<=n-1;i++)//树 n-1条边
{
int a,b;
scanf("%d%d",&a,&b);
t[a].push_back(b);
t[b].push_back(a);//
}
dfs(p);
for(int i=1;i<=n;i++)
{
if(i<n)
printf("%d ",f[i]);
else
printf("%d\n",f[i]);
}
}
return 0;
}