zoukankan      html  css  js  c++  java
  • ARC103D题解

    题意简述

    给定 (n) 个互不相同的整数 (D_i),表示一棵树每一个节点到其他所有节点的简单路径距离和。

    构造出原树,或判断这是不可能的。

    (nle 10^5)

    算法分析

    乍看上去没有任何思路,考虑先找一些性质。

    首先我们考虑两个相邻的节点 (x,y),并假设 (y)(x) 的父节点,那么不难发现 (D(x)=D(y)-siz(x)+left(n-siz(x) ight)),即 (D(x)=D(y)-2siz(x)+n)

    由这个性质,我们不难发现,所有 (D_i) 中最大的一定是一个叶子节点的 (D_i)

    因此我们考虑将这棵树自底向上构造出来。首先先对 (D_i) 从大到小排序,然后维护一个森林,存储每一棵树的根节点,树大小,树根的 (D_i) ,这样我们可以求出每一棵树要连接的父节点(D_i)。对于一个新加的节点,我们找到所有可以作为其儿子的树,连边即可。最后连 (n-1) 条边即可。

    下面我们考虑证明这个构造的正确性。首先我们要证明对于任意一棵树,都能找到一个节点,使得从这个节点所有叶子的 (D_i) 递增。

    (D_i)的递推式与 (siz) 有关,因此我们直接取树的重心,由树的重心性质不难发现,其除了其本身以外所有节点的 (2 imes siz<n),因此 (D(x)>D(y))

    接着我们要证明,如果有解,上面的构造一定能得到一个可行解。

    由于 (D_i) 互不相同,所以如果对于当前枚举的节点 (i) ,有一棵树的根 (x) 满足连边条件却不连边,以后一定没有连边的机会,因此一定要连边才可能有解。这样的构造从根到叶子 (D_i) 递增,由上证单调性可知对于任意有解的树,这样的构造一定能将其构造出来。

    但由于一些边界问题,上述构造得到的解不一定满足题意,我们需要再检验一次。

    找连边的节点可以用 set 维护,每一个元素会进入离开set一次,均摊下来复杂度为 (O(nlog n))

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 1000005
    #define maxm 2000005
    #define inf 0x3f3f3f3f
    #define int long long
    #define mod 1000000007
    #define local
    void file(string s){freopen((s+".in").c_str(),"r",stdin);freopen((s+".out").c_str(),"w",stdout);}
    template <typename Tp> void read(Tp &x){
    	int fh=1;char c=getchar();x=0;
    	while(c>'9'||c<'0'){if(c=='-'){fh=-1;}c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c&15);c=getchar();}x*=fh;
    }
    int n,m;
    struct node{
    	int id,vl;
    	bool operator <(node y)const{
    		return vl>y.vl;
    	}
    }a[maxn];
    int edf[maxn],edt[maxn],ett;
    struct nds{
    	int rt,siz,vl;
    	bool operator <(nds y)const{//按照应该的父节点di排序
    		return ((vl+2*siz-n)==(y.vl+2*y.siz-n))?(rt<y.rt):((vl+2*siz-n)<(y.vl+2*y.siz-n));
    	}
    };
    set<nds>st;
    namespace CHK{//二次检验
    	vector<int>G[maxn];
    	int d[maxn],siz[maxn];
    	void dfs1(int x,int pa){
    		siz[x]=1;
    		for(auto y:G[x]){
    			if(y==pa)continue;
    			dfs1(y,x);
    			siz[x]+=siz[y];
    			d[x]+=d[y]+siz[y];
    		}
    	}
    	void dfs2(int x,int pa){
    		for(auto y:G[x]){
    			if(y==pa)continue;
    			d[y]=d[x]-2*siz[y]+n;
    			dfs2(y,x);
    		}
    	}
    	void chk(){
    		for(int i=1;i<=ett;++i){
    			G[edf[i]].push_back(edt[i]);
    			G[edt[i]].push_back(edf[i]);
    		}
    		dfs1(1,0);dfs2(1,0);
    		for(int i=1;i<=n;++i){
    			int x=a[i].id,dd=a[i].vl;
    			if(d[x]!=dd){
    				puts("-1");
    				exit(0);
    			}
    		}
    	}
    }
    signed main(){
    	read(n);
    	for(int i=1;i<=n;++i){
    		read(a[i].vl);a[i].id=i;
    	}
    	sort(a+1,a+n+1);
    	set<nds>::iterator itl,itr,it,it0;
    	for(int i=1;i<=n;++i){
    		if(!st.size()){
    			st.insert((nds){a[i].id,1,a[i].vl});
    			continue;
    		}
    		int tvl=a[i].vl,tn=(n>>1);
    		if(n&1)++tvl;//这里是用set写不太方便的一个地方,这里强行构造出一个siz,vl使得vl+2*siz-n=di
    		itl=st.lower_bound((nds){0,tn,tvl});
    		itr=st.upper_bound((nds){n+1,tn,tvl});
    		if(itl==itr){
    			st.insert((nds){a[i].id,1,a[i].vl});
    			continue;
    		}
    		int sm=1;
    		for(it=itl;it!=itr;++it){
    			++ett;
    			edf[ett]=a[i].id;
    			edt[ett]=(*it).rt;
    			sm+=(*it).siz;
    		}
    		st.insert((nds){a[i].id,sm,a[i].vl});
    		for(it=itl;it!=itr;){
    			it0=it;++it;
    			st.erase(it0);
    		}
    	}
    	if(st.size()>1){
    		puts("-1");
    	}
    	else{
    		CHK::chk(); 
    		for(int i=1;i<=ett;++i)printf("%lld %lld
    ",edf[i],edt[i]);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    2.12 使用@DataProvider
    2.11 webdriver中使用 FileUtils ()
    Xcode8 添加PCH文件
    The app icon set "AppIcon" has an unassigned child告警
    Launch Image
    iOS App图标和启动画面尺寸
    iPhone屏幕尺寸、分辨率及适配
    Xcode下载失败 使用已购项目页面再试一次
    could not find developer disk image
    NSDate与 NSString 、long long类型的相互转化
  • 原文地址:https://www.cnblogs.com/ZigZagKmp/p/14374450.html
Copyright © 2011-2022 走看看