AT2675 [AGC018F] Two Trees (construction + bipartite graph coloring + union search)

description

Poke me to see the title

solution

The positive explanation is the Euler circuit, but it is very difficult to understand in private. If you are interested, you can read the blog of Xiangxiang mm.
Define a point if there are even number of sons, it is an odd point; if there are odd number of sons, it is an even point
For a point, each subtree itself satisfies mod 2 = 1 mod\ 2=1m o d 2 =1 of

If it is an even point, add the odd number of sons mod 2 mod\ 2m o d 2  has met the requirements, and the point weight is set to0 00
If it is a singularity, then the even-numbered sons are added and the modulo is gone, and the point weight should be set to± 1 ± 1±1

Consider the case of a subtree alone, and count yourself, the number of singularities in the entire tree should be 2 k + 1 2k+12 k+1
After a random match, there will be a single point.
This point will passuuu point up to match a certain lone ancestor

Pairs of matching points are taken as 1, − 1 1, -11,1 , bipartite graph coloring can be done

code

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 100005
int f[maxn], c[maxn], rnk[maxn];

int find( int u ) {
    
    
	if( u == f[u] ) return u;
	int fa = find( f[u] );
	c[u] ^= c[f[u]];
	return f[u] = fa;
}

void merge( int u, int v ) {
    
     //并查集按秩合并 
	int fu = find( u ), fv = find( v );
	if( fu == fv ) return;
	else if( rnk[fu] < rnk[fv] ) swap( fu, fv );
	else if( rnk[fu] == rnk[fv] ) rnk[fu] ++;
	c[fv] = c[u] ^ c[v] ^ 1;
	f[fv] = fu;
} 

struct node {
    
    
	vector < int > G[maxn];
	int siz[maxn];
	int root;
	
	void init( int n ) {
    
    
		for( int i = 1, fa;i <= n;i ++ ) {
    
    
			scanf( "%d", &fa );
			if( ~ fa ) G[fa].push_back( i ), siz[fa] ++;
			else root = i;
		}
	}
	
	int dfs( int u ) {
    
    
		vector < int > num;
		if( ! ( siz[u] & 1 ) ) num.push_back( u );//有偶数个儿子 即奇点 
		for( int i = 0;i < G[u].size();i ++ )
			num.push_back( dfs( G[u][i] ) );
		for( int i = 1;i < num.size();i += 2 ) //一定是2k+1个点 两两匹配 孤出一个点与上面祖先匹配
			merge( num[i], num[i + 1] );
		return num[0]; 
	}
	
}A, B;

int main() {
    
    
	int n;
	scanf( "%d", &n );
	A.init( n ), B.init( n );
	for( int i = 1;i <= n;i ++ )
		if( ( A.siz[i] + B.siz[i] ) & 1 ) //i点在两棵树上的奇偶性应一致 
			return ! printf( "IMPOSSIBLE\n" );
	printf( "POSSIBLE\n" );
	for( int i = 1;i <= n;i ++ ) f[i] = i;
	A.dfs( A.root ), B.dfs( B.root );
	for( int i = 1;i <= n;i ++ )
		if( ! ( A.siz[i] & 1 ) ) {
    
    
			find( i );
			if( c[i] ) printf( "1 " );
			else printf( "-1 " );
		}
		else printf( "0 " );
	return 0;
}

Guess you like

Origin blog.csdn.net/Emm_Titan/article/details/113838511