3495: PA2010 Riddle
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 279 Solved: 97
[ Submit][ Status][ Discuss]
Description
k个国家,几个城市,m条边。
要求每个国家有且仅有一个首都,每条边两端的城市至少要有一个首都。
判断是否有解, 有解输出“TAK”,无解输出"NIE"
1 < = k, N ,M , < =1000000。
Input
Output
Sample Input
6 5 2
1 2
3 1
1 4
5 2
6 2
3 3 4 2
3 1 6 5
1 2
3 1
1 4
5 2
6 2
3 3 4 2
3 1 6 5
Sample Output
TAK
HINT
Source
暴力建边n^2~岂不gg. 考虑2-Sat的一种常见优化建边方式前缀和优化(网上很多人写了前缀和以及后缀和, 但是推一下发现只用前缀和啊...). 对于某个国家的第i个城市, 如果i为首都那么就可以推出i及i之前的这个国家的城市只有一个首都是正确的, 同时推出i+1及i+1之前的这个国家的城市只有一个首都是正确的, 同时还能推出i-1及i-1之前的这个国家的城市一个首都都没有. 那么建三条边即可(反向同理). 只用判对错的2-Sat简直好写好调.
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e6;
int n, m, num, cnt, top, idx, tot, k, all;
int low[maxn], dfn[maxn], s[maxn], h[maxn], scc[maxn];
inline const int read() {
register int x = 0;
register char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
struct edge{ int nxt, v;}e[maxn << 1];
inline void add(const int &u, const int &v) {
e[++ num].v = v, e[num].nxt = h[u], h[u] = num;
e[++ num].v = u ^ 1, e[num].nxt = h[v ^ 1], h[v ^ 1] = num;
}
void dfs(int u) {
s[++ top] = u;
low[u] = dfn[u] = ++ idx;
for (int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (!dfn[v])
dfs(v), low[u] = min(low[u], low[v]);
else if (!scc[v]) low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
++ cnt;
while (s[top + 1] != u)
scc[s[top --]] = cnt;
}
}
int main() {
register int i, j, x, y, p, last;
n = read(), m = read(), k = read();
for (i = 1; i <= m; ++ i) {
x = read(), y = read();
add(x << 1 | 1, y << 1);
}
for (i = 1; i <= k; ++ i) {
p = read();
for (j = 1; j <= p; ++ j) {
++ tot;
x = read();
if (j ^ 1) {
add(x << 1, last | 1);
add(last, (n + tot) << 1);
add(x << 1, (n + tot) << 1);
} else add(x << 1, (n + tot) << 1);
last = (n + tot) << 1;
}
}
all = (n + tot) << 1 | 1;
for (i = 2; i <= all; ++ i)
if (!dfn[i]) dfs(i);
for (i = 1; i <= n; ++ i)
if (scc[i << 1] == scc[i << 1 | 1]) return puts("NIE"), 0;
puts("TAK");
return 0;
}