20211114 地图 map

Description

给定一个 \(n\) 个点 \(m\) 条边的无向图,现在有两种颜色,对每条边定色,使得每个点连的两种颜色的边数量差小于等于 \(1\)

\(n\ , m\leq 2\cdot 10 ^6\)

image

Analysis

题意就是每条边要么给连向的两个点答案 \(+1\) ,要么同时 \(-1\) ,问能不能让每个点的答案的绝对值不超过 \(1\)

刚拿到这个题的时候第一感觉是 eugene ,但是那个是定向,连向的两个点一边 \(-1\)\(+1\) ,这个是同时 \(+1\)\(-1\) ,有点关系,做法也有点像,但那个是加强版,就不去管他。

这里有个比较显眼的一个 Sub ,注意到 Subtask 3 的图好像是个欧拉回路(连不连通问题不大),然后我们想到欧拉回路上的边如果是前面一条 \(-1\) ,后面一条 \(+1\) ,这样对于每个点,无论怎么样前后两条边的答案都会抵消。

然后发现一个那啥边数为奇数的欧拉回路无论怎么 \(+1\)\(-1\) 都至少会有一个点前后两条边都是 \(+1\)\(-1\) ,这种就肯定无解,判掉就行了。

Solution

前两个 Sub 和正解没啥关系,就不去管他了。

接着 Analysis 的想法,发现一般的图就是有一些度数为奇数的点,想想怎么去避免。

删边的话不太现实,不知道删那些,干脆加边,加边,加边!而且就算有重边的话,遍历的时候肯定会挨在一起,又因为我们是在路径上 \(01\) 染色,所以就算实际上得路径不合法,这重边的贡献也会相互抵消掉,本质上也不会影响最终欧拉回路的结果。

然后发现这样的话,因为是无向图,所以无论怎么样都会有偶数个度数为奇数的点,每个点只需要额外连出去一条边。加上跑完欧拉回路后每个点的答案都是 \(0\) ,所以把多加的边删掉之后答案也不会超过 \(1\) ,肯定是满足的。

但是 Analysis 里面也说了如果是边数为奇数的欧拉回路不能做到全部答案为 \(0\) 。虽然一般的情况我们会最终去掉一些边,可能能让这个答案合法,但是为了严谨性,我们不这样去做。

那怎么办呢?啊啊啊!怎么办呀!!

这每次加边的话只加一条,可以调整边数奇偶性,然后可以开一个虚点,每次连两条边出去,这样边数奇偶性就有了保障,就可以放心的跑欧拉回路了!

时间复杂度 \(O(n)\)

Code

/*
5 5
1 2
2 3
3 4
4 5
5 3
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 10;
int n, _m, m, du[N], fst[N], tot = 1, cur[N], ans[N << 1];
bool vis[N << 1], sig[N], ljp;
struct edge {
	int nxt, fr, to;
} e[N << 1];
inline int read() {
	char ch = getchar();
	int s = 0, w = 1;
	while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {s = (s << 3) + (s << 1) + ch - '0'; ch = getchar();}
	return s * w;
}
inline void add(int u, int v) {
	e[++tot] = (edge) {fst[u], u, v};
	fst[u] = tot;
}
inline void dfs_ola(int u, int las) {
	sig[u] = 1;
	for (int i = cur[u]; i; i = cur[u]) {
		cur[u] = e[i].nxt;
		int v = e[i].to;
		if (vis[i ^ 1] || vis[i]) continue;
		vis[i] = 1;
		dfs_ola(v, i);
	}
	ans[las >> 1] = ljp; ljp ^= 1;
}
int main() {
//	freopen("map.in", "r", stdin);
//	freopen("map.out", "w", stdout);
	n = read(); _m = m = read();
	for (int i = 1, u, v; i <= m; ++i) {
		u = read(), v = read();
		add(u, v); ++du[u];
		add(v, u); ++du[v];
	}
	int now = 0;
	for (int i = 1; i <= n; ++i) if (du[i] & 1) {
		if (!now) now = i;
		else {
			if (m & 1) {
				add(i, now); add(now, i);
				++du[i]; ++du[now]; ++m; now = 0;
			}
			else {
				add(now, n + 1); add(n + 1, now);
				add(i, n + 1); add(n + 1, i);
				++du[i]; ++du[now]; m += 2; now = 0;
			}
		}
	}
	if (m & 1) {
		printf("-1\n");
		return 0;
	}
	for (int i = 1; i <= n + 1; ++i) cur[i] = fst[i];
	for (int i = 1; i <= n; ++i) {
		if (!sig[i]) dfs_ola(i, 0);
	}
	for (int i = 1; i <= _m; ++i) {
		printf("%d ", ans[i]);
	}
	return 0;
}
posted @ 2021-11-14 20:34  Illusory_dimes  阅读(24)  评论(0编辑  收藏  举报