link
-
给出 (N) 个互不相同的数 (D_i),表示树上的节点 (i) 到其他所有点的距离和。
-
请判断是否存在这样一棵树,其中每条边的长度均为 (1)。若存在请输出一种方案,否则输出 (-1)。
AT4434 [ARC103D] Distance Sums
solve
这道题第一眼没什么想法,先随便画画图
我们发现,如果从 (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;
}