洛谷 P5811 - [IOI2019] 景点划分

发布时间 2023-10-02 16:28:47作者: tzc_wk

小清新构造题。

不妨假设 \(a\le b\le c\)。显然我们会让大小为 \(a,b\) 的部分连通,这样肯定是不劣的。建出 DFS 树,考虑其重心 \(r\),如果 \(r\) 的某个子树大小 \(\ge a\),我们在这个子树内挑一个大小为 \(a\) 的连通块,在抠掉这个子树之外的部分挑一个大小为 \(b\) 的连通块即可。因为 \(r\) 是重心,所以外面的部分大小 \(\ge\dfrac{n}{2}\),而显然 \(b\le\dfrac{n}{2}\),所以一定是可以挑出来的。

否则,所有子树大小都 \(\le\dfrac{a}{2}\),如果图仅仅只是一棵树的话,那想要凑出 \(a\)\(b\) 的话都需要经过重心,此时是不可行的。但是如果是一张普通图的话,则可能可以通过非树边使得某些子树在不经过重心的情况下连通。此时我们采取这样的策略:依次考虑每个子树,DFS 一遍去掉重心的情况下,它能到达的部分,如果该连通块大小 \(\ge a\),就说明方案存在,否则方案不存在。具体构造是,不断扩展与当前子树相连相连的子树,直到连通块大小 \(\ge a\),这样我们就构造出了大小 \(=a\) 的连通块,而我们可以证明剩余部分大小 \(\ge b\),这是因为每个子树大小 \(<a\),因此我们此时选择的部分大小 \(<2a\),这样剩余部分大小 \(>n-2a=b+c-a>b\)

具体实现时候,如果我们采用以 \(1\) 为根 DFS 的方式求 DFS 方式,那么假设以 \(1\) 为根时 \(r\) 的父亲为 \(fa\),那么可以证明,在每个子树大小都 \(<a\) 的情况下,我们只用考虑与 \(fa\) 所在的子树相连的子树集合即可,这是因为 DFS 树不存在横叉边,因此所有有用的非树边都经过 \(fa\) 所在的子树。

const int MAXN=1e5;
const int MAXM=2e5;
const int INF=0x3f3f3f3f;
int n,m,A,B,C,ord[4],vis[MAXN+5],fa[MAXN+5],siz[MAXN+5],mx[MAXN+5],cent,res[MAXN+5];
struct graph{
	int hd[MAXN+5],to[MAXM*2+5],nxt[MAXM*2+5],ec;
	void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
}G,T;
void dfs(int x,int f){
	fa[x]=f;vis[x]=1;siz[x]=1;
	for(int e=G.hd[x];e;e=G.nxt[e]){
		int y=G.to[e];if(y==f||vis[y])continue;
		T.adde(x,y);T.adde(y,x);dfs(y,x);
		chkmax(mx[x],siz[y]);siz[x]+=siz[y];
	}
	chkmax(mx[x],n-siz[x]);
	if(mx[x]<mx[cent])cent=x;
}
void dfsT(int x,int f,int col,int &siz){
	if(!x||!siz)return;res[x]=col;--siz;
	for(int e=T.hd[x];e;e=T.nxt[e]){
		int y=T.to[e];if(y==f||res[y])continue;
		dfsT(y,x,col,siz);
	}
}
void dfsG(int x,int f,int col,int &siz){
	if(!x||!siz)return;
	for(int e=T.hd[x];e;e=T.nxt[e]){
		int y=T.to[e];if(y==f)continue;
		dfsG(y,x,col,siz);
	}
	for(int e=G.hd[x];e;e=G.nxt[e]){
		int y=G.to[e];
		if(!res[y]&&y!=cent)dfsT(y,x,col,siz);
	}
}
int main(){
	scanf("%d%d%d%d%d",&n,&m,&A,&B,&C);
	for(int i=1;i<=3;i++)ord[i]=i;
	if(A>B)swap(A,B),swap(ord[1],ord[2]);
	if(A>C)swap(A,C),swap(ord[1],ord[3]);
	if(B>C)swap(B,C),swap(ord[2],ord[3]);
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);++u;++v;
		G.adde(u,v);G.adde(v,u);
	}
	mx[0]=INF;dfs(1,0);siz[fa[cent]]=n-siz[cent];
	for(int e=T.hd[cent];e;e=T.nxt[e]){
		int y=T.to[e];
		if(siz[y]>=A){
			dfsT(y,cent,1,A);dfsT(cent,0,2,B);
			for(int i=1;i<=n;i++)printf("%d%c",ord[(!res[i])?3:res[i]]," \n"[i==n]);
			return 0;
		}
	}
	res[cent]=4;
	dfsT(fa[cent],0,1,A);dfsG(fa[cent],cent,1,A);
	if(A){for(int i=1;i<=n;i++)printf("0 ");}
	else{
		dfsT(cent,0,2,B);
		for(int i=1;i<=n;i++)printf("%d%c",ord[(!res[i])?3:res[i]]," \n"[i==n]);
	}
	return 0;
}