【NOIP模拟】树
题面
这道题目非常简单,由于是水题信心赛嘛,我就不多废话了。给定一棵树,每一条边连接着树上的两个点集 ,我们让这条边的魔法值为二元组 表示这两个集合中的数的最大值 (你可以认为,就是点编号的最大值)。
好像是很简单的树p呢~
那就请你来做这道题吧!欢乐送分
不过,在比赛开始前 秒,我们一不小心搞丢了这道题的输入数据。 但是,万幸的是,输出数据还在。我们请
你根据输出数据恢复这棵可怜的树
分析
又是一道构造,醉了。
因为前面那道据说送分但是无人AC让我没时间想这个题,直接输出NO走人,25分到手(血赚,前面那个题输NO只有5分23333)
其实血亏,私以为这道构造比第一道简单
好吧,还是那句话 构造题==钻空子
题让你构造树就真的构造树啊!!构造链啊!!(其实也有构造菊花图的)
首先你必须发现,给出的一组点对中,其中有一个点必然是n(显然),如果不是n,就是无答案
而我们用每个点对去除n后剩的数字构成一个序列。从小到大处理这个序列,查到每个在序列中的元素。
当前查到在序列的元素有多个,就把不在序列里且比这个元素小的点和这个元素连边。
因为是从小到大在连边,所以比前一个点大但是比当前元素小的左右两端点不会改变。
最后再连上n这个点就OK了
代码
#include<bits/stdc++.h> using namespace std; #define N 5000 int a,b,n,cnt,vis[N]; struct email{int u,v;}e[N*4]; inline void add(int u,int v){e[++cnt].u=u,e[cnt].v=v;} int main() { scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); if(a>b)swap(a,b); if(b!=n||a==b){puts("NO");return 0;} vis[a]++; } for(int i=1;i<n;i++) { if(vis[i]>1) { int last=i; for(int j=1;j<i;j++) if(!vis[j]) { vis[j]++;vis[i]--; add(j,last);last=j; if(vis[i]==1)break; } if(vis[i]==1)add(last,n); else {puts("NO");return 0;} } else if(vis[i]==1)add(i,n); } puts("YES"); for(int i=1;i<=cnt;i++)printf("%d %d\n",e[i].u,e[i].v); return 0; }
“Make my parents proud,and impress the girl I like.”