【AGC018F】Two Trees(二分图染色)

传送门


题解:

欧拉回路构造题从来不写欧拉回路

正解好像是一个欧拉回路。

但是我并不想写欧拉回路。

于是xjb搞了一个二分图染色做法。

为了方便接下来所称呼的偶点,奇点都是指儿子数量+1的奇偶性。

首先所有叶子都是奇点。

所有偶点都有奇数个儿子,考虑令偶点本身的权值为0,它的某两个儿子配对,要求一个为+1,另一个为-1。那么剩下一个儿子就是贡献到它本身的值。

这样剩下这个儿子权值没有确定,显然这个儿子子树内部也有这样一个决定权值的点存在,我们把这个点上传,在祖先的地方为其寻找匹配点。

奇点只需要把自己考虑进去就行了。

两个树都搞一遍,用带权并查集维护颜色。

显然这样匹配出来是一个二分图,因为一个点只会有两条边,一条是在树A中进行匹配产生的边,另一条是在树B中匹配产生的边,这样交错下去,显然只有经过偶数条边才会回到自己。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;T num;bool f=false;
		while(!isdigit(c=gc()))f=c=='-';num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e5+7;

int n;

int col[N],fa[N],rk[N];
inline int gf(int u){
	if(u==fa[u])return u;
	int tp=gf(fa[u]);
	col[u]^=col[fa[u]];
	return fa[u]=tp;
}
inline void mg(int u,int v){
	int fu=gf(u),fv=gf(v);
	if(fu==fv)return ;
	if(rk[fu]<rk[fv])std::swap(fu,fv);
	else if(rk[fu]==rk[fv])++rk[fu];
	col[fv]=col[u]^col[v]^1;
	fa[fv]=fu;
}

struct Tree{
	int last[N],nxt[N],to[N],ecnt;
	int son[N],rt;
	inline void adde(int u,int v){
		++son[u];
		nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
	}
	inline void init(int n){
		for(int re i=1;i<=n;++i){
			int fa=gi();
			if(fa==-1)rt=i;
			else adde(fa,i);
		}
	}
	int dfs(int u){
		std::vector<int> nd;
		if(!(son[u]&1))nd.push_back(u);
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])nd.push_back(dfs(v));
		for(int re i=1;i<nd.size();i+=2)mg(nd[i],nd[i+1]);
		return nd[0];
	}
}t1,t2;

signed main(){
#ifdef zxyoi
	freopen("two_trees.in","r",stdin);
#endif
	n=gi();t1.init(n);t2.init(n);
	for(int re i=1;i<=n;++i)if((t1.son[i]^t2.son[i])&1)puts("IMPOSSIBLE"),exit(0);
	for(int re i=1;i<=n;++i)fa[i]=i;
	t1.dfs(t1.rt);t2.dfs(t2.rt);
	puts("POSSIBLE");
	for(int re i=1;i<=n;++i)
	if(!(t1.son[i]&1))printf("%s ",(gf(i),col[i]?"1":"-1"));
	else printf("0 ");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值