【线段树分治】luogu_P5787 二分图 /【模板】线段树分治

时间:2021-08-13
本文章向大家介绍【线段树分治】luogu_P5787 二分图 /【模板】线段树分治,主要包括【线段树分治】luogu_P5787 二分图 /【模板】线段树分治使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意

有一个\(n\)个节点的图。
\(k\)时间内有\(m\)条边会出现后消失
要求出每一时间段内这个图是否是二分图。
\(n,k=10^5,m=2\times 10^5\)

思路

离线算法。根据时间来分治。

用线段树来保存覆盖了时间段\([l,r]\)的边。

对于当前线段树节点,如果这些边都添➕进图中会使这个图不是二分图,就直接退出。
如果边都➕完了,我们就继续分治,处理没有完全覆盖这个区间的边。
这就相当于在线段树上分治,即线段树分治。

至于判断二分图,可以使用扩展域并查集来处理,并且要支持撤销操作,这个用栈维护再回溯即可。

代码

#include <cstdio>
#include <vector>

int n, m, k, cnt, top;
int u[300001], v[300001], fa[600001], height[600001];
int V[300001];
std::vector<int> dat[1200001];
std::pair<int, int> st[600001];

void insert(int p, int l, int r, int L, int R, int x) {
	if (L <= l && r <= R) {
		dat[p].push_back(x);
		return;
	}
	int mid = l + r >> 1;
	if (L <= mid)
		insert(p << 1, l, mid, L, R, x);
	if (R > mid)
		insert(p << 1 | 1, mid + 1, r, L, R, x);
}

int find(int x) {//注意并查集用按秩合并,路径压缩会影响回溯
	return x == fa[x] ? x : find(fa[x]);
}

void merge(int x, int y) {
	int f1 = find(x), f2 = find(y);
	if (height[f1] > height[f2])
		std::swap(f1, f2);
	st[++top] = std::make_pair(f1, height[f1] == height[f2]);
	fa[f1] = f2;
	height[f2] += height[f1] == height[f2];
}

void solve(int p, int l, int r) {
	int flag = 1, lastop = top;
	for (int i = 0; i != dat[p].size(); i++) {
		int tmp = dat[p][i];
		int f1 = find(u[tmp]), f2 = find(v[tmp]);
		if (f1 == f2) {//不是二分图就不用继续分治,这个时间段都不是二分图
			for (int j = l; j <= r; j++)
				printf("No\n");
			flag = 0;
			break;
		}
		merge(u[tmp], v[tmp] + n);//扩展域
		merge(u[tmp] + n, v[tmp]);
	}
	if (flag) {//覆盖当前区间的边可以
		if (l == r)
			printf("Yes\n");
		else {//继续分治
			int mid = l + r >> 1;
			solve(p << 1, l, mid);
			solve(p << 1 | 1, mid + 1, r);
		}
	}
	while (top > lastop) {
		height[fa[st[top].first]] -= st[top].second;
		fa[st[top].first] = st[top].first;
		top--;
	}
}

int main() {
	scanf("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= n; i++)
		fa[i] = i, fa[i + n] = i + n;
	for (int i = 1, l, r; i <= m; i++) {
		scanf("%d %d %d %d", &u[i], &v[i], &l, &r);
		if (l ^ r)
			insert(1, 1, k, l + 1, r, i);
	}
	solve(1, 1, k);
}

原文地址:https://www.cnblogs.com/HSZGB/p/15138876.html