T1 tom
(WOJ476)
1.1 题目描述
众所周知,Tom猫对香肠非常感兴趣。有一天,Tom家里的女主人赏给了Tom一大堆香肠。这些香肠太多了,以至于Tom一顿吃不完,于是它把这些香肠串成了一棵树,树的每个节点上都有一个香肠。Tom需要给这些香肠进行编号,其中有
a
a
a个香肠需要编号为
1
,
2...
a
1,2...a
1,2...a中的不重复的编号,作为早餐肠,剩下的
b
b
b个香肠需要编号为
−
1
,
−
2...
−
b
-1,-2...-b
−1,−2...−b中的不重复的编号,作为晚餐肠。Tom每天会随机吃一顿饭,可能是早饭,也可能是晚饭。如果是吃早饭,Tom会吃掉编号绝对值最小的早餐肠,反之吃掉编号绝对值最小的晚餐肠。如果一根香肠被吃掉了,那么与它相连的树上的边都会断掉,因此剩下的香肠可能会因此变成若干棵树,即变得不再连通。这是Tom不希望发生的事。请给这些香肠编号,使得无论Tom如何安排早饭和晚饭,整棵树一直都是连通的。
1.2 输入描述
第一行三个正整数
n
,
a
,
b
n,a,b
n,a,b,代表节点的数目,早餐肠的数目,晚餐肠的数目。保证
a
+
b
=
n
a+b=n
a+b=n。
第二行开始,共
n
−
1
n-1
n−1行,每行两个正整数
u
,
v
u,v
u,v,代表树上一条边。
1.3 输出描述
共
n
n
n行,第
i
i
i行输出第
i
i
i个节点的编号。
如果存在多种编号方式,请随意输出一种。如果不存在这样的编号方式,请输出
−
1
-1
−1。
1.4 输入样例&输出样例
输入:
6 3 3 1 3 2 -3 -2 -1
1 2
2 3
2 4
4 5
4 6
输出:
1 3 2 -3 -2 -1
1.5 样例说明
对于第一个样例:
按
1
,
3
,
2
,
3
,
2
,
1
1,3,2,3,2,1
1,3,2,3,2,1编号后,无论如何安排早晚餐,香肠组成的树都是一直联通的。
另外,其它的编号方式也是可行的,比如
2
,
3
,
1
,
3
,
1
,
2
2,3,1,3,1,2
2,3,1,3,1,2等。
1.6 数据范围
对于全部的数据,
n
≤
1
0
5
,
a
+
b
=
n
,
1
≤
a
,
b
n\leq 10^5,a+b=n,1\leq a,b
n≤105,a+b=n,1≤a,b.
思路:
因为不能在按序删去任意一点后,变成森林,所以编号为正和负的点各组成一个连通块。
首先树形dp求出每一个节点的儿子个数
s
u
m
sum
sum,此时如果不存在
s
u
m
[
i
]
sum[i]
sum[i]等于
a
或
b
a或b
a或b,则无解,否则
i
至
f
a
t
h
e
r
[
i
]
i至father[i]
i至father[i]的边为正负连通块的分界,最后dfs将远离分界的节点编号的绝对值赋小,按序输出即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int s=0,f=1;char x;
for(x=getchar();!isdigit(x);x=getchar()) if(x=='-') f=-1;
for( ;isdigit(x);x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return s*f;
}
const int A=2e5+5;
int n,a,b;
int u,v;
int head[A],tot;
struct Road{int next,to;}road[A];
void ljb(int x,int y){road[++tot]={head[x],y};head[x]=tot;}
int num[A],f[A],be[A];
bool can=0;
void prepare(int fa,int x){
f[x]=fa;
for(int y=head[x];y;y=road[y].next){
int z=road[y].to;
if(fa==z) continue;
prepare(x,z);
num[x]+=num[z];
}
num[x]++;
return;
}
int morning=1,evening=1;
/* 1=morning,0=evening */
void son(int x,int fa,bool times){
for(int y=head[x];y;y=road[y].next){
int z=road[y].to;
if(z==fa) continue;
son(z,x,times);
}
if(times){
be[x]=morning;
morning++;
}
if(!times){
be[x]=-evening;
evening++;
}
return;
}
void father(int x,int fa,bool times){
for(int y=head[x];y;y=road[y].next){
int z=road[y].to;
if(z==fa) continue;
father(z,x,times);
}
if(times){
be[x]=morning;
morning++;
}
if(!times){
be[x]=-evening;
evening++;
}
return;
}
void work(int root){
if(num[root]==a){
son(root,f[root],1);
father(f[root],root,0);
return;
}
if(num[root]==b){
son(root,f[root],0);
father(f[root],root,1);
return;
}
}
signed main(){
//freopen("tom.in","r",stdin);
//freopen("tom.out","w",stdout);
n=in,a=in,b=in;
for(int i=1;i<n;i++){
u=in,v=in;
ljb(u,v),ljb(v,u);
}
prepare(0,1);
for(int i=1;i<=n;i++)
if(num[i]==a||num[i]==b){
can=1;
work(i);
break;
}
if(!can){
puts("-1");
return 0;
}
for(int i=1;i<=n;i++)
printf("%d ",be[i]);
return 0;
}