AtCoder Grand Contest 018 F - Two Trees (构造)

题面

贴图太模糊,还是给链接吧
更快的链接

题解

感觉构造题没什么好分析的,想得到怎么构造就能对,

一般的主线思路就是想什么样的情况无解,什么样的构造可以证明有解,

这道题我们就先从怎么判无解做起。

首先每棵子树的权值和都是1或-1,那么隐含了一个条件,就是每棵子树的权值和都是奇数,某个点 i i i 的所有子树权值都是奇数,同时它自己为根的子树权值也是奇数,那么就可以判断每个点权值的奇偶性,在两棵树内分别记为 f 1 [ i ] f_1[i] f1[i] f 2 [ i ] f_2[i] f2[i] (1表示为奇,0表示为偶)。

于是,最起码只要有一个点的 f 1 ≠ f 2 f_1\not=f_2 f1=f2 就可以判无解了吧。

然后,我们限定点权只能为 − 1 , 0 , 1 -1,0,1 1,0,1 之一,想想怎么构造。

一颗子树最终的权值和为 1或-1,而字数内部又有奇数个点的点权要是奇数(1或-1),那么必然除了某一个点以外,其它的 1 和 -1 都两两抵消了,我们把两两抵消的两个点之间连一条边(在第三个图上),这个就想怎么配对怎么配对了,一般是兄弟节点之间子树内最后剩下的点之间配对。

第二棵树也这么做,只不过两两抵消的点之间的边也连到第三个图上。由于每棵树在第三个图上连的边单独拿出来都是一个最大匹配,边之间不相邻,所以第三个图整体上不存在奇环,因此是个二分图,我们把它黑白染色,黑点点权为1,白点为-1,不涉及的点权为偶数的点就为0,就构造成功了。

因此,我们通过构造的方法证明了有解当且仅当每个点的 f 1 = f 2 f_1=f_2 f1=f2,且每个点的点权只要有解就能限制在 { − 1 , 0 , 1 } \lbrace-1,0,1\rbrace { 1,0,1} 以内。

CODE

#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define INF 0x7f7f7f7f
LL read() {
    
    
	LL f=1,x=0;char s = getchar();
	while(s < '0' || s > '9') {
    
    if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {
    
    x=x*10+(s-'0');s = getchar();}
	return f * x;
}
const int MOD = 1000000007;
int n,m,i,j,s,o,k;
int rt1,rt2;
int as[MAXN];
vector<int> g1[MAXN],g2[MAXN],g3[MAXN];
bool f1[MAXN],f2[MAXN],vis[MAXN];
int dfs1(int x) {
    
    
	int las = 0; f1[x] = 0;
	for(int i = 0;i < (int)g1[x].size();i ++) {
    
    
		int y = g1[x][i];
		int po = dfs1(y);
		if(las) {
    
    
			g3[las].push_back(po);
			g3[po].push_back(las);
			las = 0;
		}
		else las = po;
	}
	if(!las) las = x,f1[x] = 1;
	return las;
}
int dfs2(int x) {
    
    
	int las = 0; f2[x] = 0;
	for(int i = 0;i < (int)g2[x].size();i ++) {
    
    
		int y = g2[x][i];
		int po = dfs2(y);
		if(las) {
    
    
			g3[las].push_back(po);
			g3[po].push_back(las);
			las = 0;
		}
		else las = po;
	}
	if(!las) las = x,f2[x] = 1;
	return las;
}
void dfs3(int x,int cl) {
    
    
	vis[x] = 1;
	as[x] = cl;
	for(int i = 0;i < (int)g3[x].size();i ++) {
    
    
		int y = g3[x][i];
		if(!vis[y]) {
    
    
			dfs3(y,-cl);
		}
	}
	return ;
}
int main() {
    
    
	n = read();
	for(int i = 1;i <= n;i ++) {
    
    
		s = read();
		if(s > 0) {
    
    
			g1[s].push_back(i);
		}
		else rt1 = i;
	}
	for(int i = 1;i <= n;i ++) {
    
    
		s = read();
		if(s > 0) {
    
    
			g2[s].push_back(i);
		}
		else rt2 = i;
	}
	dfs1(rt1);
	dfs2(rt2);
	for(int i = 1;i <= n;i ++) {
    
    
		if(f1[i] != f2[i]) {
    
    
			printf("IMPOSSIBLE\n");
			return 0;
		}
		if(f1[i] && !vis[i]) {
    
    
			dfs3(i,1);
		}
	}
	printf("POSSIBLE\n");
	for(int i = 1;i <= n;i ++) {
    
    
		printf("%d ",as[i]);
	}ENDL;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43960414/article/details/113837991