[BZOJ]3495 Riddle 2-Sat 前缀和优化

来源:互联网 发布:衣服软件 编辑:程序博客网 时间:2024/05/20 08:02

3495: PA2010 Riddle

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 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

Sample Output

TAK

HINT

Source

[Submit][Status][Discuss]


HOME Back

  暴力建边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;}


原创粉丝点击