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;
}