題意:一棵個點的無權樹,給定每個點到其他所有點的距離之和,保證兩兩不同。構造或判斷無法構造一棵滿足條件的樹。
首先對於非根結點,有
所以最大的一定是葉子結點
把從大到小排序,然後用上面的式子依次找到每個點的父親,如果沒有找到輸出無解。
注意並不是由兒子的來確定它的父親是誰,它的父親以及值是早就定好了的,你只是把它找出來。這個式子是計算式而不是決定式。
因爲值是唯一的,所以這個過程是確定的,如果有解的話一定可以確定出來。
注意構造出來了不一定代表有解,如果把看成個變量,而條邊只能確定之間的關係。所以需要判斷一個點算出的是否是真正的,直接把加起來就是,判一下即可。
複雜度
#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;
}