「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;
}