• [思维构造] 题解 Distance Sums


    [思维构造] 题解 Distance Sums

    题目链接

    题目分析

    注意到给出的数是互不相同的,这点是很重要的。

    考虑重心满足所有点到重心的距离和最小,所以先排个序, (D_i) 最小的就是重心节点。

    考虑以重心为根,得出每个点的子树大小 (mbox{sz}(i)) ,如果 (u)(v) 的父亲,那么就会有 (D_v=D_u+n-2mbox{sz}(v))

    注意到 (D_i) 最大的点肯定是叶子节点,也就是说它的 (mbox{sz}) 是固定的,所以按 (D_i) 从大到小给每个节点找到它的父亲,由于 (D_i) 互不相同,从大到小为每个节点安排父亲节点是他们的父亲节点是固定的,所以每个节点的 (mbox{sz}) 也是固定的,于是我们就可以构造出这样一棵树了,最后还需要判断一下所有点到重心的距离是否满足条件。

    找父亲可以二分做,时间复杂度是 (mathcal O(nlog_2n)) 的。

    参考代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ch() getchar()
    #define pc(x) putchar(x)
    using namespace std;
    template<typename T>void read(T&x){
    	static char c;static int f;
    	for(c=ch(),f=1;c<'0'||c>'9';c=ch())if(c=='-')f=-f;
    	for(x=0;c>='0'&&c<='9';c=ch())x=x*10+(c&15);x*=f;
    }
    template<typename T>void write(T x){
    	static char q[65];int cnt=0;
    	if(x<0)pc('-'),x=-x;
    	q[++cnt]=x%10,x/=10;
    	while(x)
    		q[++cnt]=x%10,x/=10;
    	while(cnt)pc(q[cnt--]+'0');
    }
    const int maxn=100005;
    struct Node{
    	long long dis;int id;
    	Node(long long dis=0,int id=0):
    		dis(dis),id(id){}
    	bool operator < (const Node o)const{
    		return dis<o.dis;
    	}
    }P[maxn];
    int sz[maxn];
    int Find(int l,int r,long long dis){
    	while(l<r){
    		int mid=(l+r)>>1;
    		if(P[mid].dis<dis)l=mid+1;else r=mid;
    	}
    	return P[l].dis==dis?l:-1;
    }
    int pa[maxn],dp[maxn];
    int main(){
    	int n;read(n);
    	for(int i=1;i<=n;++i){
    		read(P[i].dis);P[i].id=i;
    	}
    	sort(P+1,P+n+1);
    	for(int i=n;i>=2;--i){
    		++sz[i];
    		long long sd=P[i].dis-(n-sz[i]*2);
    		int j=Find(1,i-1,sd);
    		if(~j){
    			pa[P[i].id]=P[j].id;
    			sz[j]+=sz[i];
    		}
    		else return puts("-1"),0;
    	}
    	long long sum=0;
    	dp[P[1].id]=0;
    	for(int i=2;i<=n;++i)
    		sum+=dp[P[i].id]=dp[pa[P[i].id]]+1;
    	if(sum!=P[1].dis)return puts("-1"),0;
    	for(int i=2;i<=n;++i)
    		write(P[i].id),pc(' '),write(pa[P[i].id]),pc('
    ');
    	return 0;
    }
    
    
  • 相关阅读:
    ASP.NET跨页面传值技巧总结
    C#向Sql Server中插入记录时单引号的处理 使用存储过程 .NET教程,C#语言
    在.net平台上如何创建和使用web 服务(C#)
    使用母版页时内容页如何使用css和javascript
    HTML ID和Name属性的区别
    c++/c#中的转义符
    SendMessage 启动屏幕保护程序_2
    sendmessage WM_PAINT带背景的窗体
    UPPERERR.txt
    With do 简化代码语句
  • 原文地址:https://www.cnblogs.com/lsq147/p/13930060.html
Copyright © 2020-2023  润新知