CF1386C. Joker
Solution
难得有一道可以整体二分的题。
有一个基本的思路是:考虑求出 A n s i Ans_i Ansi表示最小的右端点,满足 [ 1 , i ] ∪ [ A n s i , m ] [1,i]\cup[Ans_i,m] [1,i]∪[Ansi,m]中存在奇环。
考虑到 A n s i Ans_i Ansi序列是非减的,因此我们可以 t w o p o i n t e r s + L C T two\;pointers+LCT twopointers+LCT维护生成树以及是否存在奇环,时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
不过还有一种
O
(
n
log
2
n
)
O(n \log^2n)
O(nlog2n)的整体二分做法:
令
S
o
l
v
e
(
l
,
r
,
L
,
R
)
Solve(l,r,L,R)
Solve(l,r,L,R)表示求出
i
∈
[
l
,
r
]
,
A
n
s
i
∈
[
L
,
R
]
i\in[l,r],Ans_i\in[L,R]
i∈[l,r],Ansi∈[L,R]的所有
A
n
s
i
Ans_i
Ansi。有一个精妙的想法是:我们去保证
S
o
l
v
e
(
l
,
r
,
L
,
R
)
Solve(l,r,L,R)
Solve(l,r,L,R)时
[
1
,
l
]
∪
[
R
,
n
]
[1,l]\cup[R,n]
[1,l]∪[R,n]的边已经加入 ,那么
i
=
m
i
d
i=mid
i=mid的答案就可以通过加入
[
l
+
1
,
m
i
d
]
[l+1,mid]
[l+1,mid]以及不超过
O
(
R
−
L
)
O(R-L)
O(R−L)条边求出,然后分治下去。
总时间复杂度: O ( n log 2 n ) O(n\log^2 n) O(nlog2n)。
Code
#include <bits/stdc++.h>
using namespace std;
template<typename T> inline bool upmin(T &x, T y) { return y < x ? x = y, 1 : 0; }
template<typename T> inline bool upmax(T &x, T y) { return x < y ? x = y, 1 : 0; }
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int, int> PR;
typedef vector<int> VI;
const lod eps = 1e-9;
const lod pi = acos(-1);
const int oo = 1 << 30;
const ll loo = 1ll << 60;
const int mods = 1e9 + 7;
const int inv2 = (mods + 1) >> 1;
const int MAXN = 200005;
const int INF = 0x3f3f3f3f; //1061109567
/*--------------------------------------------------------------------*/
namespace FastIO{
constexpr int SIZE = (1 << 21) + 1;
int num = 0, f;
char ibuf[SIZE], obuf[SIZE], que[65], *iS, *iT, *oS = obuf, *oT = obuf + SIZE - 1, c;
#define gc() (iS == iT ? (iT = ((iS = ibuf) + fread(ibuf, 1, SIZE, stdin)), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush() {
fwrite(obuf, 1, oS - obuf, stdout);
oS = obuf;
}
inline void putc(char c) {
*oS ++ = c;
if (oS == oT) flush();
}
inline void getc(char &c) {
for (c = gc(); c != '<' && c != '>' && c != EOF; c = gc());
}
inline void reads(char *st) {
char c;
int n = 0;
getc(st[++ n]);
for (c = gc(); c == '<' || c == '>' ; c = gc()) st[++ n] = c;
st[n + 1] = '\0';
}
template<class I>
inline void read(I &x) {
for (f = 1, c = gc(); c < '0' || c > '9' ; c = gc()) if (c == '-') f = -1;
for (x = 0; c >= '0' && c <= '9' ; c = gc()) x = (x << 3) + (x << 1) + (c & 15);
x *= f;
}
template<class I>
inline void print(I x) {
if (x < 0) putc('-'), x = -x;
if (!x) putc('0');
while (x) que[++ num] = x % 10 + 48, x /= 10;
while (num) putc(que[num --]);
}
struct Flusher_{~Flusher_(){flush();}} io_Flusher_;
}
using FastIO :: read;
using FastIO :: putc;
using FastIO :: reads;
using FastIO :: print;
PR E[MAXN];
int f[MAXN], col[MAXN], Ans[MAXN], num[MAXN], top = 0, n, m, Case;
struct stknode{ int x, p, y, q; } stk[MAXN];
int find(int x) { return f[x] == x ? f[x] : find(f[x]); }
int getcol(int x) { return f[x] == x ? col[x] : getcol(f[x]) ^ col[x]; }
int Add(int u, int v) {
int x = find(u), y = find(v);
if (num[x] > num[y]) swap(x, y);
if (x != y) {
stk[++ top] = (stknode){x, col[x], y, num[y]};
col[x] ^= getcol(u) ^ getcol(v) ^ 1;
f[x] = y, num[y] += num[x];
return 0;
}
return (getcol(u) == getcol(v));
}
void del(int x) {
while (top > x) {
f[stk[top].x] = stk[top].x;
col[stk[top].x] = stk[top].p;
num[stk[top].y] = stk[top].q;
-- top;
}
}
void solve(int l, int r, int L, int R, int flag) {
// cout << l << " " << r << " " << L << " " << R << " " << flag << endl;
if (l > r) return;
if (flag || L == R) {
for (int i = l; i <= r ; ++ i) Ans[i] = R;
return;
}
int mid = (l + r) >> 1, lst = top, Flag = 0;
for (int i = l + 1; i <= mid ; ++ i) Flag |= Add(E[i].fi, E[i].se);
if (Flag) Ans[mid] = R;
else {
int Lst = top;
for (int i = R - 1; i >= L ; -- i)
if (Add(E[i].fi, E[i].se)) { Ans[mid] = i; break; }
del(Lst);
}
Flag |= Add(E[mid + 1].fi, E[mid + 1].se);
solve(mid + 1, r, Ans[mid], R, Flag);
del(lst);
Flag = 0;
for (int i = R - 1; i >= Ans[mid] ; -- i) Flag |= Add(E[i].fi, E[i].se);
solve(l, mid - 1, L, Ans[mid], Flag);
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("a.in", "r", stdin);
#endif
read(n), read(m), read(Case);
for (int i = 1; i <= n ; ++ i) f[i] = i, num[i] = 1;
for (int i = 1; i <= m ; ++ i) read(E[i].fi), read(E[i].se);
solve(0, m - 1, 1, m + 1, 0);
// for (int i = 1; i <= n ; ++ i) cout << Ans[i] << endl;
while (Case --) {
int l, r;
read(l), read(r);
if (Ans[l - 1] > r) putc('Y'), putc('E'), putc('S');
else putc('N'), putc('O');
putc('\n');
}
return 0;
}