【codeforces】1041E Tree Reconstruction【构造】

E. Tree Reconstruction

【题目描述】

传送门

【题解】

最后所有可行答案中肯定有一种是链。所以我们只需要构造条链就可以了。
首先我们任意切开一条边,肯定有一个联通块的最大值是n,然后n-1肯定会出现一次。否则就输NO。
我们定义关键点是在读入中出现过的点。
肯定先从小的开始,这个关键点的出现次数就是这个关键点与下个关键点之间的距离,当然这中间连的点一定要小于两边的点。
这棵树就是n为根节点,关键点大小依次递减的链。

代码如下

#include<queue>
#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=1005;
int n,que[MAXN],tl,Num[MAXN];
struct xcw{int x,y;}a[MAXN];
bool vis[MAXN];
int read(){
	int ret=0;char ch=getchar();bool f=1;
	for(;!isdigit(ch);ch=getchar()) f^=(ch^'-');
	for(; isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;
	return f?ret:-ret;
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("prob.in","r",stdin);
	freopen("prob.out","w",stdout);
	#endif
	scanf("%d",&n);
	bool t1=1,t2=0;
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		if(x==y) t1=0;
		if(x==n) que[i]=y;else que[i]=x;
		if(x!=n&&y!=n) t1=0;
		if(x==n-1||y==n-1) t2=1;
	}
	if(t1==0||t2==0){printf("NO\n");return 0;}
	sort(que+1,que+n);que[0]=tl=0;
	for(int i=1,j=1;i<n;i=j){
		que[++tl]=que[i];vis[que[i]]=1;
		for(j=i+1;j<=n&&que[i]==que[j];j++);
		Num[tl]=j-i;
	}
	que[tl+1]=n;
	int Now=1,tot=0;
	for(int i=1;i<=tl;i++){
		int lst=que[i],Y=Num[i]-1;
		while(Num[i]-1){
			while(vis[Now]&&Now<=n) Now++;vis[Now]=1;
			if(Now>que[i]){printf("NO\n");return 0;}
			a[++tot]=(xcw){lst,Now};lst=Now;Num[i]--;
		}
		if(!Y) a[++tot]=(xcw){que[i+1],que[i]};else a[++tot]=(xcw){que[i+1],Now};
	}
	if(tot!=n-1){printf("NO\n");return 0;}
	printf("YES\n");
	for(int i=1;i<=tot;i++) printf("%d %d\n",a[i].x,a[i].y);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值