考虑逆排列
p
−
1
=
q
p^{-1}=q
p−1=q,那么就是对于
∀
1
<
i
≤
n
\forall 1<i\leq n
∀1<i≤n,
q
i
q_i
qi与
max
j
=
1
i
−
1
q
j
\max_{j=1}^{i-1}q_j
maxj=1i−1qj间连了一条边。那么容易发现连出来的树是一个毛毛虫的形状,其中主链上的点是所有
q
q
q的前缀最大值。
那么显然将给定的树的直径拿出来贪心算一下即可,注意
q
1
q_1
q1可能是直径的两个端点,分别算一遍取最小的
p
p
p即可。
时间复杂度
O
(
N
)
\mathcal O(N)
O(N)。
#include <bits/stdc++.h>
using namespace std;
vector <int> e[100005];
int dep[100005],fa[100005];
int dfs1(int x) {
int s=x;
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa[x]) {
int u=e[x][i];
fa[u]=x;dep[u]=dep[x]+1;
int t=dfs1(u);
if (dep[t]>dep[s]) s=t;
}
return s;
}
int d[100005],num[100005];
bool vis[100005];
int p[100005],q[100005];
int main() {
int n;
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);
}
int rt1=dfs1(1);
fa[rt1]=dep[rt1]=0;
int rt2=dfs1(rt1),cnt=0;
for(int i=rt2;i;i=fa[i]) {
num[++cnt]=i;
vis[i]=1;
}
for(int i=1;i<=n;i++)
if (!vis[i]) {
bool ok=0;
for(int j=0;j<e[i].size();j++)
if (vis[e[i][j]]) {
d[e[i][j]]++;
ok=1;
break;
}
if (!ok) {
puts("-1");
return 0;
}
}
int s=0;
for(int i=1;i<=cnt;i++) {
int x=num[i];
for(int j=1;j<=d[x];j++) p[s+j]=s+j+1;
p[s+d[x]+1]=s+1;
s+=d[x]+1;
}
s=0;
for(int i=cnt;i>0;i--) {
int x=num[i];
for(int j=1;j<=d[x];j++) q[s+j]=s+j+1;
q[s+d[x]+1]=s+1;
s+=d[x]+1;
}
bool ok=0;
for(int i=1;i<=n;i++)
if (p[i]!=q[i]) {
ok=(p[i]<q[i]);
break;
}
if (ok) {
for(int i=1;i<=n;i++) printf("%d ",p[i]);
printf("\n");
}
else {
for(int i=1;i<=n;i++) printf("%d ",q[i]);
printf("\n");
}
return 0;
}