[AGC035B]Even Degrees

题目

点这里看题目。

分析

参考混合图欧拉回路的想法,不难想到初始给每条边随机定向。

这样如果有奇数个奇度点,就肯定无解;具体怎么证,我也不知道

接着也可以想到,由于原图连通,所以对于任意两个奇度点,都必然有一条路径连接这两个点。反转这条路径上所有边的方向,中途的点出度的奇偶性不变,而两端的点的奇偶性恰好反转。

因此可以给奇度点任意匹配,接着反转路径。由于任何的路径都是 OK 的,因此可以直接找生成树上的路径。所以我们可以对每对奇度点在树上对边进行差分,确定最终的边的方向。

小结:

  1. 初始一组任意解并进行调整的方法非常常用
  2. 反转路径上的边这一操作的度数性质比较常见;

代码

#include <cmath>
#include <cstdio>

#define rep( i, a, b ) for( int (i) = (a) ; (i) <= (b) ; ++ (i) )
#define per( i, a, b ) for( int (i) = (a) ; (i) >= (b) ; -- (i) )

const int MAXN = 1e6 + 5, MAXLOG = 20;

template<typename _T>
void read( _T &x )
{
	x = 0; char s = getchar(); int f = 1;
	while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ); s = getchar(); }
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) write( x / 10 );
	putchar( x % 10 + '0' );
}

struct Edge
{
	int to, nxt, id;
}Graph[MAXN];

int seq[MAXN];

int fr[MAXN], to[MAXN];
bool rev[MAXN];

int f[MAXN][MAXLOG];
int head[MAXN], deg[MAXN], fa[MAXN], tag[MAXN], dep[MAXN];
int N, M, cnt = 1, lg2;
bool vis[MAXN], pair[MAXN];

void MakeSet( const int siz ) { rep( i, 1, siz ) fa[i] = i; }
int FindSet( const int u ) { return fa[u] = ( fa[u] == u ? u : FindSet( fa[u] ) ); }

bool UnionSet( int u, int v ) 
{
	u = FindSet( u ), v = FindSet( v );
	if( u == v ) return false; fa[u] = v; return true;
}

void AddEdge( const int from, const int to, const int I )
{
	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
	Graph[cnt].id = I, head[from] = cnt;
}

void Init( const int u, const int fa )
{
	f[u][0] = fa, dep[u] = dep[fa] + 1;
	for( int i = head[u], v ; i ; i = Graph[i].nxt )
		if( ( v = Graph[i].to ) ^ fa ) Init( v, u );
}

void Init()
{
 	Init( 1, 0 ), lg2 = log2( N );
 	rep( j, 1, lg2 ) rep( i, 1, N ) f[i][j] = f[f[i][j - 1]][j - 1];
}

void Balance( int &u, int stp )
{
	for( int i = 0 ; ( 1 << i ) <= stp ; i ++ )
		if( stp & ( 1 << i ) ) u = f[u][i];
}

int LCA( int u, int v )
{
	if( dep[u] > dep[v] ) Balance( u, dep[u] - dep[v] );
	if( dep[u] < dep[v] ) Balance( v, dep[v] - dep[u] );
	if( u == v ) return u;
	rep( i, lg2, 0 ) if( f[u][i] ^ f[v][i] ) u = f[u][i], v = f[v][i];
	return f[u][0];
}

void Recovery( const int u, const int fa )
{
	for( int i = head[u], v ; i ; i = Graph[i].nxt )
		if( ( v = Graph[i].to ) ^ fa )
		{
			Recovery( v, u ), tag[u] += tag[v];
			rev[Graph[i].id] = tag[v] & 1;
		}
}

int main()
{
	read( N ), read( M );
	MakeSet( N );
	rep( i, 1, M ) 
	{
		read( fr[i] ), read( to[i] ), deg[fr[i]] ++;
		if( UnionSet( fr[i], to[i] ) ) AddEdge( fr[i], to[i], i ), AddEdge( to[i], fr[i], i );
	}
	int tot = 0;
	rep( i, 1, N ) if( deg[i] & 1 ) seq[++ tot] = i;
	if( tot & 1 ) return puts( "-1" ), 0;
	Init(); int half = tot >> 1;
	rep( i, 1, half ) 
		tag[seq[i]] ++, tag[seq[i + half]] ++, tag[LCA( seq[i], seq[i + half] )] -= 2;
	Recovery( 1, 0 );
	rep( i, 1, M )
		if( rev[i] ) printf( "%d %d\n", to[i], fr[i] );
		else printf( "%d %d\n", fr[i], to[i] );
	return 0;
}
posted @ 2021-01-12 16:51  crashed  阅读(88)  评论(0编辑  收藏  举报