1. 程式人生 > 實用技巧 >#樹,搜尋#NOIP2020.9.26模擬tom

#樹,搜尋#NOIP2020.9.26模擬tom


分析

考慮最極端的情況也就是TOM天天吃早餐腸或者晚餐腸, 那麼早餐腸和晚餐腸應分別構成一個互不相交連通塊, 所以題目轉換成是否有一個點的子樹大小為$a$或$b$, 將這個點與它父親的邊斷開就可以分別編號了


程式碼

#include <cstdio>
#include <cctype>
#include <queue>
#define rr register
using namespace std;
const int N=100011;
struct node{int y,next;}e[N<<1];
int a[N],n,k=1,son[N],rt1,rt2,now,as[N],A,B;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void dfs1(int x,int fa){
	son[x]=1;
	for (rr int i=as[x];i;i=e[i].next)
	    if (e[i].y!=fa) dfs1(e[i].y,x),son[x]+=son[e[i].y];
    if (son[x]==A) rt1=x,rt2=fa;
        else if (son[x]==B) rt1=fa,rt2=x;
}
inline void dfs2(int x,int opt,int fa){
	a[x]=opt*(now--);
	for (rr int i=as[x];i;i=e[i].next)
	    if (!a[e[i].y]&&e[i].y!=fa)
		    dfs2(e[i].y,opt,fa);
}
signed main(){
	freopen("tom.in","r",stdin);
	freopen("tom.out","w",stdout);
	n=iut(); A=iut(); B=iut();
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut();
		e[++k]=(node){y,as[x]},as[x]=k;
		e[++k]=(node){x,as[y]},as[y]=k;
	}
	dfs1(1,0);
	if (!rt1&&!rt2) return !printf("-1");
	now=A,dfs2(rt1,1,rt2),now=B,dfs2(rt2,-1,rt1);
	for (rr int i=1;i<=n;++i){
		if (a[i]<0) putchar('-'),print(-a[i]);
		    else print(a[i]);
		putchar(10);
	}
	return 0;
}