[hdu 5354] Bipartite Graph 分治 并查集
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[hdu 5354] Bipartite Graph 分治 并查集相关的知识,希望对你有一定的参考价值。
题意
给定一张 $n$ 个点, $m$ 条边的无向图.
问删去每个点后, 原图是不是二分图.
$1 \le n, m \le {10} ^ 5$ .
分析
一个图是二分图 $\Leftrightarrow$ 图中不存在奇环.
判定一个图是不是二分图, 可以使用并查集, 多维护一个当前点与父亲的关系的量 bond .
删除每一个点, 我们有两种维度: 区间加法, 区间减法.
这里考虑区间加法, 即考虑分治.
由于要支持撤销, 所以使用按秩合并的并查集. 注意按照大小合并... 按深度合并会 TLE ...
实现
支持撤销: ①以直接开一个栈, 并且记录一下时间戳; ②或者整体地观察一下哪些地方发生了修改, 修改回去就好了.
#include <cstdio> #include <cstring> #include <cstdlib> #include <cctype> #include <algorithm> using namespace std; #define F(i, a, b) for (register int i = (a); i <= (b); i++) const int N = 200005; int nT; int n, m; int tot, nx[N], hd[N], v[N]; int f[N], b[N], d[N], top; struct Data { int id, b, d; inline Data(int _id = 0, int _b = 0, int _d = 0): id(_id), b(_b), d(_d) {} }s[N]; char ans[N]; namespace Input { const int S = 2000000; char s[S], *h = s+S, *t = h; inline char getchr(void) { if (h == t) fread(s, 1, S, stdin), h = s; return *h++; } inline int rd(void) { int f = 1; char c = getchr(); for (; !isdigit(c); c = getchr()) if (c == ‘-‘) f = -1; int x = 0; for (; isdigit(c); c = getchr()) x = x*10+c-‘0‘; return x*f; } } using Input::rd; inline void Init(int x, int y) { nx[++tot] = hd[x], hd[x] = tot, v[tot] = y; } inline void Find(int x, int &par, int &bond) { if (f[x] == x) par = x, bond = 0; else Find(f[x], par, bond), bond ^= b[x]; } inline bool Union(int x, int y) { int fx, bx, fy, by; Find(x, fx, bx); Find(y, fy, by); if (fx == fy) return bx == (1 ^ by); else { s[++top] = Data(fx, b[fx], d[fx]); s[++top] = Data(fy, b[fy], d[fy]); if (d[fx] > d[fy]) swap(fx, fy), swap(bx, by), swap(x, y); f[fx] = fy, b[fx] = (1 ^ by) ^ bx; d[fy] += d[fx]; return true; } } inline void Undo(int lim) { for (; top > lim; s[top--] = Data()) { int x = s[top].id; f[x] = x, b[x] = s[top].b, d[x] = s[top].d; } } void Solve(int L, int R) { if (L == R) { ans[L] = ‘1‘; return; } int M = (L+R)>>1; int rec = top; bool tag = true; for (int x = L; x <= M && tag; x++) for (int k = hd[x]; k > 0 && tag; k = nx[k]) if (!(x <= v[k] && v[k] <= R) && !Union(x, v[k])) tag = false; if (!tag) F(x, M+1, R) ans[x] = ‘0‘; else Solve(M+1, R); Undo(rec); tag = true; for (int x = R; x > M && tag; x--) for (int k = hd[x]; k > 0 && tag; k = nx[k]) if (!(L <= v[k] && v[k] <= x) && !Union(x, v[k])) tag = false; if (!tag) F(x, L, M) ans[x] = ‘0‘; else Solve(L, M); Undo(rec); } int main(void) { #ifndef ONLINE_JUDGE freopen("hdu5354.in", "r", stdin); freopen("hdu5354.out", "w", stdout); #endif nT = rd(); F(t, 1, nT) { tot = 0, memset(hd, 0, sizeof hd); n = rd(), m = rd(); F(i, 1, m) { int u = rd(), v = rd(); Init(u, v), Init(v, u); } F(i, 1, n) f[i] = i, b[i] = 0, d[i] = 1; top = 0; memset(ans, 0, sizeof ans); Solve(1, n); printf("%s\n", ans+1); } return 0; }
以上是关于[hdu 5354] Bipartite Graph 分治 并查集的主要内容,如果未能解决你的问题,请参考以下文章
Bipartite Graph hdu 5313 bitset 并查集 二分图
[LeetCode] Is Graph Bipartite? 是二分图么?