先考虑一个点的总体访问顺序。我们发现一个点的子树内部可以划分为若干个根节点单调递增的连通块,满足连通块内部编号均小于根。于是我们访问的时候会依次访问这些连通块。对于两棵子树,我们会把连通块按根的编号归并起来访问,加入一个根节点会将根的编号最小的几个连通块与它合并。可以用线段树合并简单支持维护这些连通块,并记录它们的大小。
再考虑计算
c
i
c_i
ci。对于点
i
i
i,它到
1
1
1号点路径上的所有节点均需访问。删除这部分节点后,我们得到若干个连通块,同样划分为根节点单调递增的子连通块。简单分析可以知道一个根为
x
x
x的连通块被访问当且仅当存在
y
>
x
y>x
y>x满足
y
y
y在
x
x
x到
1
1
1的路径与
i
i
i到
1
1
1的路径的交上,且不能为交最底下的节点。利用预处理的线段树同样容易计算。
时间复杂度
O
(
N
log
N
)
\mathcal O(N\log N)
O(NlogN)。
#include <bits/stdc++.h>
using namespace std;
namespace SGT {
const int Maxn=20000000;
int ch[Maxn][2],sumv[Maxn],tot;
inline int cpynode(int o) {
tot++;
ch[tot][0]=ch[o][0];ch[tot][1]=ch[o][1];
sumv[tot]=sumv[o];
return tot;
}
int update(int l,int r,int o,int p,int q) {
o=cpynode(o);
sumv[o]+=q;
if (l==r) return o;
else {
int m=((l+r)>>1);
if (m>=p) ch[o][0]=update(l,m,ch[o][0],p,q);
else ch[o][1]=update(m+1,r,ch[o][1],p,q);
return o;
}
}
int erase(int l,int r,int o,int p) {
if (r<=p) return 0;
else {
o=cpynode(o);
int m=((l+r)>>1);
if (m>=p) ch[o][0]=erase(l,m,ch[o][0],p);
else {
ch[o][0]=0;
ch[o][1]=erase(m+1,r,ch[o][1],p);
}
sumv[o]=sumv[ch[o][0]]+sumv[ch[o][1]];
return o;
}
}
int merge(int l,int r,int x,int y) {
if (!x) return y;
if (!y) return x;
int o=++tot,m=((l+r)>>1);
ch[o][0]=merge(l,m,ch[x][0],ch[y][0]);
ch[o][1]=merge(m+1,r,ch[x][1],ch[y][1]);
sumv[o]=sumv[ch[o][0]]+sumv[ch[o][1]];
return o;
}
int query(int l,int r,int o,int p) {
if (!o) return 0;
if (l==r) return sumv[o];
else {
int m=((l+r)>>1);
if (m>=p) return query(l,m,ch[o][0],p);
else return sumv[ch[o][0]]+query(m+1,r,ch[o][1],p);
}
}
}
vector <int> e[200005];
int n;
int root[200005];
void dfs1(int x,int fa) {
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa) {
int u=e[x][i];
dfs1(u,x);
root[x]=SGT::merge(1,n,root[x],root[u]);
}
int v=SGT::query(1,n,root[x],x)+1;
root[x]=SGT::erase(1,n,root[x],x);
root[x]=SGT::update(1,n,root[x],x,v);
}
int maxn[200005],ans[200005];
void dfs2(int x,int fa) {
if (x>1) {
ans[x]=ans[fa]+1;
if (fa>1) ans[x]-=SGT::query(1,n,root[x],maxn[fa]);
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa) {
int u=e[x][i];
ans[x]+=SGT::query(1,n,root[u],maxn[x]);
}
}
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa) {
int u=e[x][i];
maxn[u]=max(maxn[x],x);
dfs2(u,x);
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(1,0);
dfs2(1,0);
for(int i=2;i<=n;i++) printf("%d ",ans[i]);
printf("\n");
return 0;
}