P6684 [BalticOI 2020 Day1] 小丑 题解
不难发现对于一个特定的 \(\text{l}\) 而言,\(\text{r}\) 的答案具有单调性。
所以就可以很自然的想到二分。
由于需要对所有的 \(\text{l}\) 都进行统计答案。
只用普通的二分复杂度会炸掉,所以就可以想到使用整体二分。
思路
首先考虑如何判断奇环。
对于这部分内容,可以考虑一边加边,一边判断奇环。
使用可撤销并查集维护。
如果此时加的边在同一连通块内,直接判断奇偶。
若不在同一个连通块则合并两个连通块,更新奇偶。
至于整体二分的内容可以直接套板子了。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
int n , m , q , top , ans , fa[N] , dep[N] , val[N] , siz[N] , stk[N] , sum[N];
pair<int , int> e[N];
#define fir first
#define sec second
void solve(int l , int r , int L , int R);
inline int read()
{
int asd = 0 , qwe = 1; char zxc;
while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
return asd * qwe;
}
inline int gf(int x)
{
if(x == fa[x])
return x;
int rt = gf(fa[x]);
dep[x] = dep[fa[x]] ^ val[x];
return rt;
}
inline void calc(int x , int y)
{
if(!x) return;
int fx = gf(x) , fy = gf(y);
if(fx == fy)
return ans |= (dep[x] == dep[y]) , void();
bool flag = (dep[x] == dep[y]);
x = fx , y = fy;
if(siz[x] < siz[y]) swap(x , y);
fa[y] = x , val[y] = flag;
siz[x] += siz[y] , stk[++top] = y;
}
inline void del(int x)
{
while(top > x)
{
int y = stk[top--];
siz[fa[y]] -= siz[y];
fa[y] = y , val[y] = dep[y] = 0;
}
}
inline void cl()
{
ans = top = 0;
for(int i = 1;i <= n;i++)
fa[i] = i , dep[i] = val[i] = 0 , siz[i] = 1;
}
int main()
{
n = read() , m = read() , q = read() , cl();
for(int i = 1;i <= m;i++)
{
e[i].fir = read() , e[i].sec = read();
}
int x = 0;
for(int i = 1;i <= m;i++)
{
calc(e[i].fir , e[i].sec);
if(ans)
{
for(int j = i;j <= m;j++)
sum[j] = m + 1;
x = i;
break;
}
}
if(!ans)
{
while(q--) puts("NO");
return 0;
}
cl();
solve(0 , x - 1 , 1 , m + 1);
for(int i = 1;i <= q;i++)
{
int l = read() , r = read();
puts(sum[l - 1] <= r ? "NO" : "YES");
}
return 0;
}
inline void solve(int l , int r , int L , int R)
{
if(L + 1 == R || l > r)
{
for(int i = l;i <= r;i++)
sum[i] = L;
return;
}
int mid = (L + R) / 2 , ltop = top , lans = ans;
for(int i = R - 1;i >= mid && !ans;i--)
calc(e[i].fir , e[i].sec);
int topl = top , ansl = ans , lmid = min(r , mid - 1);
for(int i = l;i <= lmid;i++)
{
calc(e[i].fir , e[i].sec);
if(ans)
{
lmid = i - 1;
break;
}
}
ans = ansl , del(topl);
solve(l , lmid , L , mid);
ans = lans , del(ltop);
for(int i = l;i <= lmid;i++)
calc(e[i].fir , e[i].sec);
solve(lmid + 1 , r , mid , R);
ans = lans , del(ltop);
}