题意:一棵个点的无权树,给定每个点到其他所有点的距离之和,保证两两不同。构造或判断无法构造一棵满足条件的树。
首先对于非根结点,有
所以最大的一定是叶子结点
把从大到小排序,然后用上面的式子依次找到每个点的父亲,如果没有找到输出无解。
注意并不是由儿子的来确定它的父亲是谁,它的父亲以及值是早就定好了的,你只是把它找出来。这个式子是计算式而不是决定式。
因为值是唯一的,所以这个过程是确定的,如果有解的话一定可以确定出来。
注意构造出来了不一定代表有解,如果把看成个变量,而条边只能确定之间的关系。所以需要判断一个点算出的是否是真正的,直接把加起来就是,判一下即可。
复杂度
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <utility>
#define MAXN 100005
using namespace std;
typedef long long ll;
typedef pair<ll,int> pi;
ll read()
{
ll ans=0;
char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
pi p[MAXN];
int siz[MAXN],fa[MAXN];
ll d[MAXN];
int main()
{
int n=read();
for (int i=1;i<=n;i++) p[i]=make_pair(read(),i),siz[i]=1;
sort(p+1,p+n+1);
ll sum=0;
for (int i=n;i>1;i--)
{
ll t=p[i].first-n+2*siz[p[i].second];
int k=lower_bound(p+1,p+n+1,make_pair(t,0))-p;
if (p[k].first!=t) return puts("-1"),0;
fa[p[i].second]=p[k].second,siz[p[k].second]+=siz[p[i].second];
sum+=siz[p[i].second];
}
if (sum!=p[1].first) return puts("-1"),0;
for (int i=1;i<=n;i++) if (fa[i]) printf("%d %d\n",fa[i],i);
return 0;
}