\(\text{Problem}:\)Distance Sums
\(\text{Solution}:\)?
显然 \(D_{i}\) 最小的结点是树的重心。以重心为原树的根,则 \(D_{i}\) 最大的结点一定是树的叶子结点。由于 \(x\rightarrow fa_{x}\) 的关系是可以被唯一确定的,所以考虑从叶子结点开始,从下往上构造原树。
考虑现在要确定 \(x\) 的父亲,那么 \(x\) 的子树应该已经建立好了,就可以直接算出 \(\Delta D\),找到权值对应的父亲即可。如果找不到显然无解。
注意到一点,构造过程中我们只用到了 \(\Delta D\) 的性质,故最后需要从原树任意一个点开始 DFS 一遍来 check 距离和是否与给定的 \(D_{i}\) 匹配(只需判断一个点是否满足即可)。时间复杂度 \(O(n\log n)\)。
\(\text{Code}:\)
#include <bits/stdc++.h>
//#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=200010;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) w=-1; ch=getchar(); }
while(ch>=‘0‘&&ch<=‘9‘) s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,siz[N],sum;
struct Node { int d,id; }a[N];
inline bool cp(Node x,Node y) { return x.d<y.d; }
vi e[N]; vpi ans;
void DFS(int x,int dep)
{
sum+=dep;
for(auto i:e[x]) DFS(i,dep+1);
}
signed main()
{
n=read();
for(ri int i=1;i<=n;i++) a[i].d=read(), a[i].id=i, siz[i]=1;
sort(a+1,a+1+n,cp);
for(ri int i=n;i>1;i--)
{
int w=a[i].d+siz[a[i].id]-(n-siz[a[i].id]);
Node fa=*lower_bound(a+1,a+1+n,(Node){w,0ll},cp);
if(fa.d!=w) return puts("-1")&0;
ans.eb(mk(fa.id,a[i].id));
e[fa.id].eb(a[i].id);
siz[fa.id]+=siz[a[i].id];
}
DFS(a[1].id,0);
if(sum!=a[1].d) return puts("-1")&0;
for(auto i:ans) printf("%lld %lld\n",i.fi,i.se);
return 0;
}