AT4434 [ARC103D] Distance Sums 题解

  • 给出 (N) 个互不相同的数 (D_i),表示树上的节点 (i) 到其他所有点的距离和。

  • 请判断是否存在这样一棵树,其中每条边的长度均为 (1)。若存在请输出一种方案,否则输出 (-1)

AT4434 [ARC103D] Distance Sums

solve

这道题第一眼没什么想法,先随便画画图

借用一下cz的图

我们发现,如果从 (u) 变化到 (v) 相当于 (u) 左边的点的距离 (+1) ,(v) 右边的点的距离 (-1)

所以

[Delta D=size[u]-sive[v]=size[u]-(n-size[u])=2 imes size[u]-n ]

得出 (D_v=2 imes size[u]-n+D_u)

这个柿子告诉我们,只要我们知道了 (D_u) ,就可以逆推 (D_v)

然后我们要思考几个性质

  • (D_i) 最大的肯定是一个叶节点

  • (D_i) 最小的肯定是树的重心

所以我们从大到小排序,从叶节点网上找,如果找到就建边,如果找不到那就无解(显然,如果找不到就不能满足这个关系)

找到根节点,也就是重心时需要判断一下是否成立,因为思考这样一件事情

我们其实已知了 (n-1)(Delta D) ,需要确定 (n) 个变量,所以我们只能确定他们之间的关系,需要确定一个变量,那么所有变量就可以确定了

于是我们可以判一下重心(其实其他的也可以)(sum size[i]=D_ ext{根节点})

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;
typedef long long LL;
LL size[maxn],ans[maxn][2],dis,len;
int N;
struct node{
	LL d;int id;
	node(){} 
	node(LL d,int x):d(d),id(x){};
	bool operator <(const node b)const {return d>b.d;}
}D[maxn];
inline LL read(){
	LL ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
int main(){
//	freopen("AT4434.in","r",stdin);
//	freopen("AT4434.out","w",stdout);
	N=read();
	for(int i=1;i<=N;i++) D[i]=node(read(),i),size[i]=1;
	sort(D+1,D+1+N);
	for(int i=1;i<N;i++){
		LL now_D=D[i].d-N+(size[i]<<1);
		int pos=lower_bound(D+1,D+1+N,node(now_D,0))-D;
		if(D[pos].d!=now_D) return printf("-1
",0),0;
		++len;ans[len][0]=D[i].id,ans[len][1]=D[pos].id;
		size[pos]+=size[i];dis+=size[i];
	}
	if(dis!=D[N].d) return printf("-1
",0),0;
	for(int i=1;i<=len;i++)
		printf("%lld %lld
",ans[i][0],ans[i][1]);
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/15521754.html