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