题意
填边使得树的两点之间距离可以遍历 所有整数。
题解
证明
1
分配数字给边,对于一棵树,如果要使得根节点到每个点的距离分别为
有这样的解决方法,首先分配最上面的结点即根节点的孩子,
到
,对于这些孩子的孩子,分别是
,减去前面的前缀和即可,只要你保证,是排好序的,这样就不会出现负值。
2
对于以重心为根节点的树,你的每棵子树节点数都
我们能否分成两部分,每一部分都有至少
的结点。
我们分离的时候,排序子树大小,选前
个刚好大于等于
。
刚好不满足的左边子树大小和是
,
是加上满足了,
是右边的
即
显然
3
在满足了第
点,我们就可以分成左右部分
、
。
左边的距离是
,右边的距离是
左边表示的距离是
。
右边第一个,
,结合左边之后,
,刚好接上第二个。
最后能表示的距离是,
,因为
,
最小的距离是:
根据以上三点,其实好像 、 就够了,但是要证明满足了 ,右边还存在子树,所以…
接下来就是先求重心,算子树大小,排序,分别把左右的处理了即可。
#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
#define inf 1e18
using namespace std;
typedef long long ll;
const int maxn = 405000;
vector<int>G[maxn];
int n,sz[maxn],mx=0x3f3f3f3f,rt=0;
int val[maxn];
void dfs1(int u,int fa){
sz[u]=1;
int tmp=0;
for(auto v:G[u]){
if(v==fa)continue;
dfs1(v,u);
tmp=max(tmp,sz[v]);
sz[u]+=sz[v];
}
tmp=max(tmp,n-sz[u]);
if(tmp<mx){
mx=tmp;
rt=u;
}
}
void dfs2(int u,int fa){
sz[u]=1;
for(auto v:G[u]){
if(v==fa)continue;
dfs2(v,u);
sz[u]+=sz[v];
}
}
int base,tot;
pair<int,int>p[maxn];
void dfs(int u,int fa){
cout<<fa<<" "<<u<<" "<<tot*base-val[fa]<<endl;
val[u]=tot*base;
tot++;
for(auto v:G[u]){
if(v==fa)continue;
dfs(v,u);
}
}
int main(){
cin>>n;
FOR(i,1,n-1){
int u,v;
sf(u),sf(v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,-1),dfs2(rt,-1);
FOR(i,1,G[rt].size())p[i]=make_pair(sz[G[rt][i-1]],G[rt][i-1]);
int m=G[rt].size();
sort(p+1,p+1+m);
int mid=0,ret=0;
FOR(i,1,m){
ret+=p[i].first;
if(ret>=(n-1)/3){
mid=i;
break;
}
}
//FOR(i,1,m)cout<<p[i].second<<" "<<p[i].first<<endl;
//cout<<rt<<endl;
tot=1,base=1;
FOR(i,1,mid)dfs(p[i].second,rt);
tot=1,base=ret+1;
FOR(i,mid+1,m)dfs(p[i].second,rt);
}