agc018F Two Tree

20 篇文章 0 订阅
16 篇文章 0 订阅

agc018F Two Tree

Solution

  • 这是一道神奇的结论题。

  • 首先你可以手玩一下,可以发现如果根据一个节点儿子的个数可以确定当前权值的奇偶性,如果在两棵树中奇偶性不同则无解。

  • 进一步的可以感受到如果满足上面的条件只需要 − 1 , 0 , 1 -1,0,1 1,0,1就可以构造出来。

  • 考虑关键的在于未确定的 − 1 , 1 -1,1 1,1,我们需要一个东西来平衡子树内的权值。

  • 对于这种看起来是线性的构造问题,一般需要用图论、连边来解决。

  • 在我们本就不多的图论知识中,可以用欧拉回路或二分图染色来解决它。

欧拉回路
  • 不妨考虑关键的奇点 ( − 1 / 1 ) (-1/1) (1/1),我们用欧拉回路走出来的边的方向来确定是 − 1 -1 1还是 1 1 1
  • 考虑对于奇数点将两棵树点相连,再加一个虚点,向两棵树的根连边,剩下的都是树上的边。
  • 直接在这个图上跑欧拉回路,对于横插边左到右为 1 1 1,否则为 − 1 -1 1
  • 可以发现对于一个点的子树内,如果不考虑父亲边,一定是进一个出一个, + 1 , − 1 +1,-1 +1,1相互抵消,那么考虑上父亲边贡献就是 1 / − 1 1/-1 1/1了。
二分图染色
  • 考虑对于一个子树内,一定有 2 K + 1 2K+1 2K+1个奇点(为 1 / − 1 1/-1 1/1),考虑它们两两相消,最后留下一个就是对当前子树的根节点的贡献。
  • 不妨对于两棵树都以某种方法匹配,使得对于每个子树都有 K K K对匹配。
  • 将两棵树匹配的边分别设为红边和蓝边,钦定连了边的两个点权值不同,再将两棵树的相同标号点合并,显然这样没有奇环,那么就构造完了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 200005
#define maxm 1000005
using namespace std;

int n,i,j,k,du[maxn],v[maxn];
int em,e[maxm],nx[maxm],ls[maxn],bz[maxm];

void insert(int x,int y){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; du[x]++;
	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; du[y]++;
}

int d[maxm];
void dfs(int x){
	while (ls[x]){
		int i=ls[x],y=e[i];
		if (!bz[i]){
			bz[i]=bz[i^1]=1,ls[x]=nx[ls[x]];
			dfs(y);
		} else ls[x]=nx[ls[x]];
	}
	d[++d[0]]=x;
}

int main(){
	freopen("ceshi.in","r",stdin);
	scanf("%d",&n),em=1;
	for(i=1;i<=n;i++) scanf("%d",&k),insert(i,(k<0)?0:k);
	for(i=1;i<=n;i++) scanf("%d",&k),insert(i+n,(k<0)?0:(k+n));
	for(i=1;i<=n;i++) if ((du[i]&1)!=(du[i+n]&1)) printf("IMPOSSIBLE"),exit(0);
	for(i=1;i<=n;i++) if (du[i]&1) insert(i,i+n);
	dfs(0);	
	for(i=1;i<d[0];i++) if (d[i]&&d[i+1]&&abs(d[i]-d[i+1])==n)
		v[min(d[i],d[i+1])]=(d[i]<d[i+1])?-1:1;
	printf("POSSIBLE\n");
	for(i=1;i<=n;i++) printf("%d ",v[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值