[HDU 5354] Bipartite Graph

来源:互联网 发布:nginx转发配置 编辑:程序博客网 时间:2024/06/05 10:24

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5354

题意: 给出n个点m条边的无向图, 要你求出哪些点满足在原图中删掉该点后是一个二分图, 输出一个01序列, 1表示这个点被删后是个二分图。(1n,m105)

思路:考虑用黑白染色来判断二分图。 使用分治的思想, 用并查集维护每个点的颜色。对于一个区间[l, r], 所有两端点都不在该区间内的边, 无论删掉该区间的任一个点这些边都将留在图中, 用这些边进行黑白染色, 如果出现冲突则[l, r]中的点答案都是0, 不用再递归子区间。 否则, 保留当前并查集的样子, 继续递归左右子区间, 这些边也因为已经考虑过不用再考虑了, 直到l与r相等时这个点答案才是1。 记得每次递归回来要把并查集回溯到原本的状态。 为了方便操作, 并查集不要路径压缩, 为了防止超时还要按秩合并。

PS:注意将两个并查集合并时, 根据原本的染色情况, 有一个集合可能要打上反转标记。

#include <queue>#include <cstdio>#include <cstdlib>#include <algorithm>#define ls (x << 1)#define rs (x << 1 | 1)#define mid ((l + r) >> 1)const int N = (int)1e5 + 10;const int M = (int)2e6 + 10;using namespace std;int n, m;int fa[N], sz[N], bj[N], ans[N];vector<pair<int, int> > edge[N << 2];int* stk[M]; int top, val[M];int modf(int *x, int y){    stk[++ top] = x; val[top] = *x;    return (*x) = y;}void recall(int aim){    while (top != aim) {(*stk[top]) = val[top]; top --;}}pair<int, int > find(int x){    int val = 0;    while (fa[x] != x) val ^= 1 ^ bj[x], x = fa[x];    return make_pair(x, val ^ bj[x]);}void unnion(int x, int y, int z){    if (sz[x] < sz[y]) swap(x, y);    modf(&fa[y], x);    modf(&sz[x], sz[x] + sz[y]);    modf(&bj[y], bj[y] ^ z);}bool in(int x, int l, int r){    return l <= x && x <= r;}void solve(int, int, int);void work(int, int, int, vector<pair<int, int> > &);void solve(int l, int r, int x){    if (l == r) {ans[l] = 1; return;}    vector<pair<int, int> > ().swap(edge[ls]);    vector<pair<int, int> > ().swap(edge[rs]);    vector<pair<int, int> > tmp[2];    for (int j = 0; j < edge[x].size(); j ++){        int u = edge[x][j].first, v = edge[x][j].second;        if (in(u, l, mid) || in(v, l, mid))  edge[ls].push_back(edge[x][j]);        else tmp[0].push_back(edge[x][j]);        if (in(u, mid + 1, r) || in(v, mid + 1, r)) edge[rs].push_back(edge[x][j]);        else tmp[1].push_back(edge[x][j]);    }    work(l, mid, ls, tmp[0]);    work(mid + 1, r, rs, tmp[1]);}void work(int l, int r, int x, vector<pair<int, int > > & tmp){    int _top = top; bool flag = 0;    for (int j = 0; j < tmp.size(); j ++){        int u = tmp[j].first, v = tmp[j].second;        pair<int, int > r1 = find(u), r2 = find(v);        if (r1.first == r2.first){            if (r1.second == r2.second) {flag = 1; break;}        }        else unnion(r1.first, r2.first, r1.second != r2.second);    }    if (flag){        for (int i = l; i <= r; i ++) ans[i] = 0;    }    else solve(l, r, x);    recall(_top);}int main(){    int T;    for (scanf("%d", &T); T --; ){        scanf("%d %d", &n, &m);        for (int i = 1; i <= n; i ++) fa[i] = i, sz[i] = 1, bj[i] = 0;        vector<pair<int, int> > ().swap(edge[1]);        for (int i = 1, u, v; i <= m; i ++){            scanf("%d %d", &u, &v);            edge[1].push_back(make_pair(u, v));        }        solve(1, n, 1);        for (int i = 1; i <= n; i ++) printf("%d", ans[i]);        puts("");    }    return 0;}