[BZOJ3495]PA2010 Riddle[2-SAT]
对于一个国家内部,每个点都要向剩下的所有点连边,会有\(O(n^2)\)条边
学习了前缀和优化建图的新姿势 在每个点拆成两个的基础上,再开两个点 \(i_3\),\(i_4\)表示前缀\([1,i]\)中有/没有首都
这个blog讲得比较详细
struct Edge {
int v, next;
} G[MAXN << 3]; int head[MAXN << 2], sta[MAXN << 2], top, n, m, bel[MAXN << 2], idx, dfn[MAXN << 2], low[MAXN << 2], k, u, v, C, ins[MAXN << 2], tar;
inline void add(int u, int v) {
static int tot = 0;
G[++tot] = (Edge) {v, head[u]}; head[u] = tot;
}
inline int g(int x, int y) {
return ((x - 1) << 2) + y;
}
inline void tarjan(int u) {
low[u] = dfn[u] = ++idx;
ins[sta[++top] = u] = 1;
for (int i = head[u]; i; i = G[i].next) {
int v = G[i].v;
if (!dfn[v])
tarjan(v), chmin(low[u], low[v]);
else if (ins[v]) chmin(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
++tar; int v;
do {
v = sta[top--];
ins[v] = 0;
bel[v] = tar;
} while (v ^ u);
}
}
int main() {
#ifdef LOCAL_DEBUG
// freopen("data.in", "r", stdin), freopen("data.out", "w", stdout);
Dbg = 1; uint tim1 = clock();
#endif
in, n, m, k;
while (m--) {
in, u, v;
add(g(u, 2), g(v, 1)), add(g(v, 2), g(u, 1));
}
while (k--) {
int las = -1, x;
in, C, las;
while (--C) {
in, x;
add(g(x, 1), g(las, 4)), add(g(las, 3), g(x, 3)), add(g(x, 4), g(las, 4)), add(g(las, 3), g(x, 2));
las = x;
}
}
lop(i,1,n) add(g(i, 1), g(i, 3)), add(g(i, 4), g(i, 2));
lop(i,1,n<<2) if (!dfn[i]) tarjan(i);
for(int i = 1; i <= 4 * n; i += 2)
if (bel[i] == bel[i + 1]) return puts("NIE"), 0;
puts("TAK");
#ifdef LOCAL_DEBUG
fprintf(stderr, "\ntime:%.5lfms", (clock() - tim1) / (1.0 * CLOCKS_PER_SEC) * 1000);
#endif
return 0;
}