#题目大意
一颗n个节点的树,边有边权。
求一个字典序最小的排列p
使得
∑
d
i
s
(
i
,
p
i
)
\sum dis(i,pi)
∑dis(i,pi)最小
#思考
∑
d
i
s
(
i
,
p
i
)
=
∑
d
e
p
i
+
d
e
p
p
i
−
2
∗
d
e
p
l
c
a
(
i
,
p
i
)
=
2
∗
∑
d
e
p
i
−
2
∗
∑
d
e
p
l
c
a
(
i
,
p
i
)
\sum dis(i,pi)=\sum dep_i+dep_{pi}-2*dep_{lca(i,pi)}=2*\sum dep_i-2*\sum dep_{lca(i,pi)}
∑dis(i,pi)=∑depi+deppi−2∗deplca(i,pi)=2∗∑depi−2∗∑deplca(i,pi)
假如我们选定重心作为根,前面部分已经固定了,而显然可以使得后面部分为0。
接下来解决字典序最小的问题。
我们把root删去,剩余若干颗子树。
贪心选取,每次都希望给pi选一个最小的j。
但我们还得保证合法,即i和j不能在同一个子树里。
同时,还得保证之后存在合法解。
思考什么时候有合法解。
假设目前已经确定了排列的前i项,一个子树里有t个大于i的节点,这些节点对应配对一定还没找好,这个子树里还有x个未配对的节点,目前总共有n-i个未配对节点,不能配对同一个子树里的,因此实际可配对的有n-i-x个,还未配对的t个节点必须有配对。
所以
t
+
x
<
=
n
−
i
t+x<=n-i
t+x<=n−i
那么当一个子树出现
t
+
x
=
n
−
i
t+x=n-i
t+x=n−i时,就很关键了,因为i在不断变大,因此右边会减小,如果左边不能随之减小,就会不合法。而可以知道每次一个子树t和x只可能其中一个减了1,因此这个等式其实就一直满足了!
所以我们用set维护所有子树的t+x,每次查看是否存在满足等式的子树,设该子树为p,那么接下来,如果i’在p子树内(t会减一),则可以正常做,否则,我们为其寻找的配对j’必须在p子树内(x会减一)。
找配对的话,可以用线段树维护,同一个子树内按编号从小到大放入一个序列中,每次指针往后移即可。
至于根是一个棘手的问题,根和任意都能配对,所以根要特殊考虑一下。
注意特判n=1。
#include<cstdio>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct dong{
int x,y;
friend bool operator <(dong a,dong b){
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
} zlt;
multiset<dong> s;
multiset<dong>::iterator it;
int tree[maxn*4];
int h[maxn],go[maxn*2],dis[maxn*2],next[maxn*2],belong[maxn];
int a[maxn],L[maxn],R[maxn],zz[maxn],tt[maxn],xx[maxn],size[maxn],ans[maxn],id[maxn],dy[maxn];
ll dep[maxn];
int i,j,k,l,t,n,m,top,tot,cnt,root,czy,p,q;
bool pp;
ll now;
void add(int x,int y,int z){
go[++tot]=y;
dis[tot]=z;
next[tot]=h[x];
h[x]=tot;
}
void dg(int x,int y){
int t=h[x];
size[x]=1;
while (t){
if (go[t]!=y){
dg(go[t],x);
size[x]+=size[go[t]];
}
t=next[t];
}
}
void dfs(int x,int y){
int t=h[x];
while (t){
if (go[t]!=y){
dep[go[t]]=dep[x]+(ll)dis[t];
dfs(go[t],x);
}
t=next[t];
}
}
void travel(int x,int y){
R[belong[x]]=++top;
a[top]=x;
tt[belong[x]]++;xx[belong[x]]++;
int t=h[x];
while (t){
if (go[t]!=y){
belong[go[t]]=belong[x];
travel(go[t],x);
}
t=next[t];
}
}
void change(int p,int l,int r,int a,int b){
if (l==r){
tree[p]=b;
return;
}
int mid=(l+r)/2;
if (a<=mid) change(p*2,l,mid,a,b);else change(p*2+1,mid+1,r,a,b);
tree[p]=min(tree[p*2],tree[p*2+1]);
}
int query(int p,int l,int r,int a,int b){
if (a>b) return n+1;
if (l==a&&r==b) return tree[p];
int mid=(l+r)/2;
if (b<=mid) return query(p*2,l,mid,a,b);
else if (a>mid) return query(p*2+1,mid+1,r,a,b);
else return min(query(p*2,l,mid,a,mid),query(p*2+1,mid+1,r,mid+1,b));
}
int main(){
scanf("%d",&n);
if (n==1){
printf("0\n");
printf("1\n");
return 0;
}
fo(i,1,n-1){
scanf("%d%d%d",&j,&k,&l);
add(j,k,l);add(k,j,l);
}
dg(1,0);
root=1;k=0;
while (1){
t=h[root];
while (t){
if (go[t]!=k&&size[go[t]]>n/2){
k=root;
root=go[t];
break;
}
t=next[t];
}
if (!t) break;
}
dfs(root,0);
fo(i,1,n) now+=dep[i];
now*=2;
t=h[root];
while (t){
id[go[t]]=++cnt;
dy[cnt]=go[t];
belong[go[t]]=go[t];
L[go[t]]=zz[go[t]]=top+1;R[go[t]]=top;
travel(go[t],root);
sort(a+L[go[t]],a+R[go[t]]+1);
t=next[t];
}
fo(i,1,cnt) change(1,1,cnt,i,a[L[dy[i]]]);
fo(i,1,cnt){
zlt.x=tt[dy[i]]+xx[dy[i]];zlt.y=dy[i];
s.insert(zlt);
}
zlt.x=n;zlt.y=0;
it=s.lower_bound(zlt);
if (it!=s.end()&&(*it).x==n){
czy=1;
p=(*it).y;
}
pp=0;
fo(i,1,n){
if (!czy){
zlt.x=n-i+1;zlt.y=0;
it=s.lower_bound(zlt);
if (it!=s.end()&&(*it).x==n-i+1){
czy=1;
p=(*it).y;
}
}
if (i==root){
if (!czy){
j=tree[1];
if (!pp) j=min(j,root);
ans[i]=j;
if (j==root){
pp=1;
continue;
}
l=belong[j];
xx[l]--;
zlt.x=tt[l]+xx[l]+1;zlt.y=l;
s.erase(s.find(zlt));
zlt.x--;
s.insert(zlt);
zz[l]++;
if (zz[l]<=R[l]) change(1,1,cnt,id[l],a[zz[l]]);else change(1,1,cnt,id[l],n+1);
}
else{
j=a[zz[p]++];
ans[i]=j;
if (zz[p]<=R[p]) change(1,1,cnt,id[p],a[zz[p]]);else change(1,1,cnt,id[p],n+1);
}
continue;
}
if (!czy){
k=belong[i];
tt[k]--;
zlt.x=tt[k]+xx[k]+1;zlt.y=k;
s.erase(s.find(zlt));
zlt.x--;
s.insert(zlt);
j=min(query(1,1,cnt,1,id[k]-1),query(1,1,cnt,id[k]+1,cnt));
if (!pp) j=min(j,root);
ans[i]=j;
if (j==root){
pp=1;
continue;
}
l=belong[j];
xx[l]--;
zlt.x=tt[l]+xx[l]+1;zlt.y=l;
s.erase(s.find(zlt));
zlt.x--;
s.insert(zlt);
zz[l]++;
if (zz[l]<=R[l]) change(1,1,cnt,id[l],a[zz[l]]);else change(1,1,cnt,id[l],n+1);
}
else if (czy==1){
k=belong[i];
if (k==p){
j=min(query(1,1,cnt,1,id[k]-1),query(1,1,cnt,id[k]+1,cnt));
if (!pp) j=min(j,root);
ans[i]=j;
if (j==root){
pp=1;
continue;
}
l=belong[j];
zz[l]++;
if (zz[l]<=R[l]) change(1,1,cnt,id[l],a[zz[l]]);else change(1,1,cnt,id[l],n+1);
}
else{
j=a[zz[p]++];
ans[i]=j;
if (zz[p]<=R[p]) change(1,1,cnt,id[p],a[zz[p]]);else change(1,1,cnt,id[p],n+1);
}
}
}
printf("%I64d\n",now);
fo(i,1,n) printf("%d ",ans[i]);
}