「BalticOI 2020」小丑

预处理出 \(f_i\) 表示最大的使得在加入所有 \([1,i)\or [j,m]\) 中的边后存在奇环的最大 \(j\)

显然 \(f\) 满足单调性,于是可以整体二分。

对于分治区间 \([l,r]\),已知所有 \(\{f_l...f_r\}\in [x,y]\),那么暴力计算出 \(f_{mid}\),然后递归分治。

暴力计算时用并查集判断奇环即可。需要支持回撤操作,所以使用可撤销并查集。

注意: 由于存在 \([1,i)\) 中的边已经构成奇环的特殊情况,在 \(x=y\) 时不能直接 return!

#include <cstdio>
#include <algorithm>
#define gc (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 65536, stdin), p1 == p2) ? EOF : *p1 ++)

char buf[65536], *p1, *p2;
inline int read() {
	int x = 0;
	char ch;
	while ((ch = gc) < 48);
	do x = x * 10 + ch - 48; while ((ch = gc) >= 48);
	return x;
}
struct node {int x, y;} stk[200005];
int fa[200005], from[200005], to[200005], dis[200005], sze[200005], f[200005], n, m, q, top;

node getval(int x) {
	int sum = 0;
	while (fa[x] != x) sum ^= dis[x], x = fa[x];
	return node{x, sum};
}
inline bool merge(int x, int y) {
	node fx = getval(x), fy = getval(y), tmp;
	if (fx.x == fy.x) return fx.y == fy.y;
	if (sze[fx.x] < sze[fy.x]) tmp = fx, fx = fy, fy = tmp;
	fa[fy.x] = fa[fx.x], dis[fy.x] = fx.y ^ fy.y ^ 1, sze[fx.x] += sze[fy.x];
	stk[++ top] = node{fx.x, fy.x}; return false;
}

void rollback(int x) {
	while (top > x) fa[stk[top].y] = stk[top].y, sze[stk[top].x] -= sze[stk[top].y], dis[stk[top].y] = 0, -- top;
}
void solve(int l, int r, int x, int y) {
	if (l > r || x > y) return;
	int mid = l + r >> 1, now = top;
	bool flag = false;
	for (int i = l; i < mid; ++ i) flag |= merge(from[i], to[i]);
	if (flag) {
		for (int i = mid; i <= r; ++ i) f[i] = m + 1;
		rollback(now), solve(l, mid - 1, x, y);
		return;
	}
	int suftop = top;
	for (int i = y; i >= x && i >= mid; -- i)
		if (flag |= merge(from[i], to[i])) {f[mid] = i; break;}
	rollback(suftop);
	if (merge(from[mid], to[mid])) for (int i = mid + 1; i <= r; ++ i) f[i] = m + 1;
	else solve(mid + 1, r, f[mid], y);
	rollback(now), now = top;
	for (int i = y; i > f[mid]; -- i) merge(from[i], to[i]);
	solve(l, mid - 1, x, f[mid]);
	rollback(now);
}

int main() {
	n = read(), m = read(), q = read();
	for (int i = 1; i <= n; ++ i) fa[i] = i, sze[i] = 1;
	for (int i = 1; i <= m; ++ i) from[i] = read(), to[i] = read();
	solve(1, m, 1, m);
	for (int i = 1, l, r; i <= q; ++ i) l = read(), r = read(), puts(r < f[l] ? "YES" : "NO");
	return 0;
}
posted @ 2022-03-06 09:55  zqs2020  阅读(53)  评论(0编辑  收藏  举报