[AGC035B]Even Degrees
题目
点这里看题目。
分析
参考混合图欧拉回路的想法,不难想到初始给每条边随机定向。
这样如果有奇数个奇度点,就肯定无解;具体怎么证,我也不知道
接着也可以想到,由于原图连通,所以对于任意两个奇度点,都必然有一条路径连接这两个点。反转这条路径上所有边的方向,中途的点出度的奇偶性不变,而两端的点的奇偶性恰好反转。
因此可以给奇度点任意匹配,接着反转路径。由于任何的路径都是 OK 的,因此可以直接找生成树上的路径。所以我们可以对每对奇度点在树上对边进行差分,确定最终的边的方向。
小结:
- 初始一组任意解并进行调整的方法非常常用;
- 反转路径上的边这一操作的度数性质比较常见;
代码
#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;
}