【hdu 5354】Bipartite Graph【分治 并查集】

2 篇文章 0 订阅
1 篇文章 0 订阅

给一张无向图,问删掉点i后改图是否为二分图。

Solve(l, r)表示要求l到r的答案。在并查集中先加上l~mid的边,Solve(mid + 1, r),回溯。同理递归到Solve(l, mid)。

并查集要按秩合并。

也可用线段树(动态维护图连通性)。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
using namespace std;
typedef long long LL;
const int N = 100005;
struct Edge { int y, nex, z1, z2, z; } g[N * 2];
int T, n, m, pos[N], sz, par[N], sum[N], l, ans[N], p1[N];
void Init(int x, int y) { g[++ sz].y = y, g[sz].nex = pos[x], pos[x] = sz; }
int Find(int x) { return (par[x] == x) ? x : (l = l ^ p1[x], Find(par[x])); }
bool Check(int l1, int r1, int l2, int r2) {
	bool fl = 0;
	Rep(x, l1, r1) {
		RepE(i, x) {
			int y = g[i].y;
			if (y > r2 || y < l2) {
				int lx, ly, x0, y0;
				l = 0, x0 = Find(x), lx = l;
				l = 0, y0 = Find(y), ly = l;
				if (x0 != y0) {
					if (sum[x0] > sum[y0]) swap(x0, y0);
					par[x0] = y0;
					g[i].z1 = x0, g[i].z2 = y0, g[i].z = sum[y0];
					p1[x0] = ((lx + ly) % 2 == 0);
					sum[y0] += sum[x0];
				} else {
					g[i].z1 = -1;
					if ((lx + ly) % 2 == 0) fl = 1;
				}
			} else g[i].z1 = -1;
		}
	}
	return fl;
}
void Solve(int l, int r) {
	if (l == r) { ans[l] = 1; return ; }
	int mid = l + r >> 1;
	bool fl = Check(l, mid, mid + 1, r);
	if (fl) Rep(i, mid + 1, r) ans[i] = 0;
	else Solve(mid + 1, r);
	Rep(x, l, mid) {
		RepE(i, x) {
			int x0 = g[i].z1, y0 = g[i].z2;
			// cout << x0<<" "<<y0<<endl;
			if (x0 == -1) continue ;
			sum[y0] = min(sum[y0], g[i].z);
			par[x0] = x0;
		}
	}
	fl = Check(mid + 1, r, l, mid);
	if (fl) Rep(i, l, mid) ans[i] = 0;
	else Solve(l, mid);
	Rep(x, mid + 1, r) {
		RepE(i, x) {
			int x0 = g[i].z1, y0 = g[i].z2;
			if (x0 == -1) continue ;
			sum[y0] = min(sum[y0], g[i].z);
			par[x0] = x0;
		}
	}
}
int main()
{
	scanf ("%d", &T);
	while (T --) {
		scanf ("%d%d", &n, &m);
		Rep(i, 1, n) par[i] = i, sum[i] = 1, pos[i] = 0; sz = 0;
		Rep(i, 1, m) {
			int x, y;
			scanf ("%d%d", &x, &y);
			Init(x, y), Init(y, x);
		}
		Solve(1, n);
		Rep(i, 1, n) printf("%d", ans[i]);
		puts("");
	}
    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值