[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 并查集 二分图

HDU 2063 过山车 二分图最大匹配(模板题)

785.Is Graph Bipartite?

[LeetCode] Is Graph Bipartite? 是二分图么?

785. Is Graph Bipartite?( 判断是否为二分图)

java 使用BFS的Bipartite