Tom
题目描述
众所周知,Tom 猫对香肠非常感兴趣。有一天,Tom 家里的女主人赏给了Tom 一大堆香肠。这些香肠太多了,以至于Tom 一顿吃不完,于是它把这些香肠串成了一棵树,树的每个节点上都有一个香肠。
Tom 需要给这些香肠进行编号,其中有 aa 个香肠需要编号为 1,2,\cdots,a1,2,⋯,a 中的不重复的编号,作为早餐肠,剩下的 bb 个香肠需要编号为-1,-2,\cdots,-b−1,−2,⋯,−b中的不重复的编号,作为晚餐肠。
Tom 每天会随机吃一顿饭,可能是早饭,也可能是晚饭。如果是吃早饭,Tom 会吃掉编号绝对值最小的早餐肠,反之吃掉编号绝对值最小的晚餐肠。
如果一根香肠被吃掉了,那么与它相连的树上的边都会断掉,因此剩下的香肠可能会因此变成若干棵树,即变得不再连通。这是Tom 不希望发生的事。
请给这些香肠编号,使得无论Tom 如何安排早饭和晚饭,整棵树一直都是连通的。
输入格式
第一行三个正整数 n,a,bn,a,b,代表节点的数目,早餐肠的数目,晚餐肠的数目。保证 a + b = na+b=n
第二行开始,共 n-1n−1 行,每行两个正整数 u,vu,v,代表树上一条边。
输出格式
共 nn 行,第 ii 行输出第 ii 个节点的编号。
如果存在多种编号方式,请随意输出一种。如果不存在这样的编号方式,请输出 -1−1。
样例输入1
6 3 3
1 2
2 3
2 4
4 5
4 6
样例输出1
1
3
2
-3
-2
-1
样例1 说明
编号后,无论如何安排早晚餐,香肠组成的树都是一直联通的。
另外,其它的编号方式也是可行的,比如2,3,1,-3,-1,-2 等。
思路
- 题目大意:一棵树只断掉一条边,剩下的两个连同快分别有a,b个节点
- 注意:判断时要分别判断a,b;flag标记返回判断两次,否则会重复赋值
代码
#include <iostream>
#include <cstdio>
#define maxn 100005
using namespace std;
int n,a,b,head[maxn],cnt,siz[maxn],num[maxn],ka,kb,flag;
struct fdfdfd{int next,to;}e[maxn<<1];
void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
void dfs3(int x,int pre)
{
num[x]=ka--;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==pre) continue;
dfs3(v,x);
}
}
void dfs2(int x,int pre)
{
num[x]=kb++;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==pre) continue;
dfs2(v,x);
}
}
void dfs1(int x,int pre)
{
if(flag) return;
siz[x]=1;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==pre) continue;
dfs1(v,x);
if(flag) return;
siz[x]+=siz[v];
}
if(siz[x]==a) dfs3(x,pre),dfs2(pre,x),flag=1;
else if(siz[x]==b) dfs2(x,pre),dfs3(pre,x),flag=1;
}
int main()
{
scanf("%d%d%d",&n,&a,&b); ka=a; kb=-b;
for(int i=1,u,v;i<n;++i) scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
dfs1(1,0);
if(!flag) puts("-1");
else
for(int i=1;i<=n;++i) printf("%d ",num[i]);
return 0;
}