P5782 [POI2001] 和平委员会

P5782 [POI2001] 和平委员会

2-sat 的模板的变形,在代码上改改就好了。

\(x_i\in[0,1]\) 表示第 \(i\) 个政党是否出第 \(2i\) 的代表,\(0\) 则出 \(2i-1\)\(1\) 则出 \(2i\) 的代表。

对于第 \(a,b\) 之间的仇恨,我们可以计算出他们分别所在的政党,并连边就好了。

代码跟模板几乎一样,难怪这道题是蓝。

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define ll long long
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;

inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') f = c == '-' ? -1 : f, c = getchar();
	while (c >= '0' && c <= '9') x = (x<<3)+(x<<1)+(c^48), c = getchar();
	return x*f;
}

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

const int N = 2e6+5;
int n, m, cnt, idx, top, c[N], dfn[N], low[N], stk[N], ins[N];
vector <int> E[N], scc[N];

inline void tarjan(int x) {
	dfn[x] = low[x] = ++idx, stk[++top] = x, ins[x] = 1;
	for (int y:E[x]) {
		if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
		else if (ins[y]) low[x] = min(low[x], dfn[y]);
	}
	if (dfn[x] == low[x]) {
		++cnt; int y;
		do {
			y = stk[top--], ins[y] = 0;
			c[y] = cnt, scc[cnt].pb(y);
		} while (x != y);
	}
}

int main() {
	n = read(), m = read();
	while (m--) {
		int x = read(), y = read();
		int i = x+1>>1, j = y+1>>1, a = !(x&1), b = !(y&1);
		if (a && b) E[i+n].pb(j), E[j+n].pb(i);
		else if (a && !b) E[i+n].pb(j+n), E[j].pb(i);
		else if (!a && b) E[i].pb(j), E[j+n].pb(i+n);
		else E[i].pb(j+n), E[j].pb(i+n);
	}
	for (int i = 1; i <= n<<1; ++i) if (!dfn[i]) tarjan(i);
	for (int i = 1; i <= n; ++i) if (c[i] == c[i+n]) puts("NIE"), exit(0);
	for (int i = 1; i <= n; ++i) write(c[i] < c[i+n] ? (i<<1)-1 : i<<1), enter;
	return 0;
}
posted @ 2023-12-27 13:56  123wwm  阅读(35)  评论(0)    收藏  举报