NOIP2020.9.26模拟tom

NOIP2020.9.26模拟tom

Description

众所周知,Tom 猫对香肠非常感兴趣。
有一天,Tom 家里的女主人赏给了 Tom 一大堆香肠。这些香肠太多了,以至于 Tom 一顿吃不完,
于是它把这些香肠串成了一棵树,树的每个节点上都有一个香肠。
Tom 需要给这些香肠进行编号,其中有 a 个香肠需要编号为 1,2···a 中的不重复的编号,作为早餐
肠,剩下的 b 个香肠需要编号为 −1,−2··· − b 中的不重复的编号,作为晚餐肠。
Tom 每天会随机吃一顿饭,可能是早饭,也可能是晚饭。如果是吃早饭,Tom 会吃掉编号绝对值最
小的早餐肠,反之吃掉编号绝对值最小的晚餐肠。
如果一根香肠被吃掉了,那么与它相连的树上的边都会断掉,因此剩下的香肠可能会因此变成若干
棵树,即变得不再连通。这是 Tom 不希望发生的事。
请给这些香肠编号,使得无论 Tom 如何安排早饭和晚饭,整棵树一直都是连通的。

Input

输入文件名为 tom.in。
第一行三个正整数 n,a,b,代表节点的数目,早餐肠的数目,晚餐肠的数目。保证 a + b = n。
第二行开始,共 n − 1 行,每行两个正整数 u,v,代表树上一条边。

Output

输出文件名为 tom.out。
共 n 行,第 i 行输出第 i 个节点的编号。
如果存在多种编号方式,请随意输出一种。如果不存在这样的编号方式,请输出 −1。

Sample Input

6 3 3
1 2
2 3
2 4
4 5
4 6

Sample Output

1
3
2
-3
-2
-1

Data Constraint

Hint

对于第一个样例:
编号后,无论如何安排早晚餐,香肠组成的树都是一直联通的。
另外,其它的编号方式也是可行的,比如 2,3,1,−3,−1,−2 等。

题解

考虑极限数据,全吃晚餐肠或早餐肠。
发现要使树还是一棵完整的树,得将树分为大小为a和b的两棵完整的树
用dfs分树,以分出树的子节点作为树的根,从叶子节点考试编号就可以了

code

#include<cstdio>
#include<cctype>
#include<cstdlib>
#define N 100101
#define R register int
using namespace std;
int vis[N],ans[N],size[N],to[N*2],next[N*2],head[N],sig;
int last,n,a,b,x1,x2,d[N];
inline void read(int &x){
	x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
inline void add(R x,R y){to[++last]=y,next[last]=head[x],head[x]=last;}
void dfs(R u,R t){
	if(x1||x2)return;
	size[u]=1;
	for(R i=head[u];i;i=next[i])
	if(to[i]!=t)dfs(to[i],u),size[u]+=size[to[i]];
	if(size[u]==a)x1=u,x2=t;
	if(size[u]==b)x1=t,x2=u;
}
void bfs(int u){
	int h=0,t=1,tot=1;
	d[1]=u;
	while(h++<t)
		for(R i=head[d[h]];i;i=next[i])
		if(!vis[to[i]])vis[to[i]]=1,d[++t]=to[i];
	for(R i=t;i;--i)ans[d[i]]=sig*(tot++); 
}
int main(){
	read(n),read(a),read(b);
	int x,y;
	for(R i=1;i<n;++i)read(x),read(y),add(x,y),add(y,x);
	dfs(1,1),vis[x1]=vis[x2]=1;
	if(x1==0){
		printf("-1");
		return 0;
	}
	sig=1,bfs(x1),sig=-1,bfs(x2);
	for(R i=1;i<=n;++i)printf("%d\n",ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值