【ARC103D】Distance Sums【樹論】【構造】

題意:一棵nn個點的無權樹,給定每個點ii到其他所有點的距離之和did_i,保證did_i兩兩不同。構造或判斷無法構造一棵滿足條件的樹。

n105n\leq 10^5

首先對於非根結點uu,有

du=dfausizu+(nsizu)d_u=d_{fa_u}-siz_u+(n-siz_u)

所以dd最大的一定是葉子結點

dd從大到小排序,然後用上面的式子依次找到每個點的父親,如果沒有找到輸出無解。

注意並不是由兒子的dd來確定它的父親是誰,它的父親以及dd值是早就定好了的,你只是把它找出來。這個式子是計算式而不是決定式。

因爲dd值是唯一的,所以這個過程是確定的,如果有解的話一定可以確定出來。

注意構造出來了不一定代表有解,如果把dd看成nn個變量,而n1n-1條邊只能確定dd之間的關係。所以需要判斷一個點算出的dd是否是真正的dd,直接把sizsiz加起來就是drootd_{root},判一下即可。

複雜度O(nlogn)O(n\log n)

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章