「BalticOI 2020」小丑
阿新 • • 發佈:2022-03-06
預處理出 \(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; }