双指针+LCT.
在二分图那道题中,有一种用 LCT 维护奇环的方法.
该题的做法和那道题相似.
对于 $i$,维护 $left[i]$ 表示当删除 $i$ 时最靠左的端点使得删掉 $[left[i]+1,i]$ 后仍然存在奇环.
那么最后判断答案的时候就看 $(l,r)$ 中的 $l$ 是否大于 $left[r]$ 即可.
由于删掉边一定不会使答案更优,所以 $i$ 增加时 $left[i]$ 不会减小,故 $[left[i],i]$ 满足双指针性质(即不存在包含的情况)
将边分为两类:
1. 由于 $i$ 变大被删掉的.
2. 由于双指针中左端点的移动被加入的.
显然对于 $1$ 类边希望出现时间越晚越好,对于 $2$ 类边没有要求.
根据上述结论,我们在预处理边的时候贪心加入即可(即加不进去就不加)
然后双指针移动的时候去替换结束时间最小的边,类似最大生成树.
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 400008
#define ll long long
#define ls s[x].ch[0]
#define rs s[x].ch[1]
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
const int inf=100000000;
int det[N];
int left[N],sta[N<<1],vis[N<<1],n,m,Q;
struct Edge {
int u,v,t;
Edge(int u=0,int v=0,int t=0):u(u),v(v),t(t){}
}a[N],arr[N];
struct data {
int ch[2],rev,f,v,id,si,t;
}s[N<<2];
inline int get(int x) { return s[s[x].f].ch[1]==x; }
inline int isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x; }
void pushup(int x) {
s[x].id=x;
s[x].si=(x<=n)+s[ls].si+s[rs].si;
if(ls&&s[s[ls].id].t<s[s[x].id].t) {
s[x].id=s[ls].id;
}
if(rs&&s[s[rs].id].t<s[s[x].id].t) {
s[x].id=s[rs].id;
}
}
void mark(int x) {
s[x].rev^=1,swap(ls,rs);
}
void pushdown(int x) {
if(s[x].rev) {
if(ls) mark(ls);
if(rs) mark(rs);
s[x].rev=0;
}
}
void rotate(int x) {
int old=s[x].f,fold=s[old].f,which=get(x);
if(!isr(old)) {
s[fold].ch[s[fold].ch[1]==old]=x;
}
s[old].ch[which]=s[x].ch[which^1];
if(s[old].ch[which]) s[s[old].ch[which]].f=old;
s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold;
pushup(old),pushup(x);
}
void splay(int x) {
int u=x,v=0,fa;
for(sta[++v]=u;!isr(u);u=s[u].f) {
sta[++v]=s[u].f;
}
for(;v;--v) pushdown(sta[v]);
for(u=s[u].f;(fa=s[x].f)!=u;rotate(x))
if(s[fa].f!=u) {
rotate(get(fa)==get(x)?fa:x);
}
}
void access(int x) {
for(int y=0;x;y=x,x=s[x].f) {
splay(x),rs=y,pushup(x);
}
}
void makert(int x) {
access(x),splay(x),mark(x);
}
void split(int x,int y) {
makert(x),access(y),splay(y);
}
int find(int x) {
access(x),splay(x);
while(ls) pushdown(x),x=ls;
splay(x);
return x;
}
void ADD(int x,int y) {
makert(x),s[x].f=y;
}
void DEC(int x,int y) {
makert(x),access(y),splay(y);
s[y].ch[0]=s[x].f=0;
pushup(y);
}
void exi(int lst) {
if(lst==0) {
for(int i=1;i<=Q;++i) {
int x,y;
scanf("%d%d",&x,&y);
printf("NO
");
}
exit(0);
}
}
int main() {
// setIO("input");
int x,y,z;
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=m;++i) {
scanf("%d%d",&x,&y);
arr[i]=Edge(x,y,i);
}
int lst=0;
a[0].t=inf;
for(int i=1;i<=n;++i) {
s[i].t=inf;
s[i].id=i;
}
for(int i=m;i>=1;--i) {
x=arr[i].u;
y=arr[i].v;
a[i]=arr[i];
if(find(x)==find(y)) {
split(x,y);
if(s[y].si&1) {
lst=i;
break;
}
}
else {
int now=n+i;
s[now].v=i;
s[now].t=i;
pushup(now);
vis[i]=1;
ADD(x,now),ADD(y,now);
}
}
int tot=n+m;
exi(lst);
int p=1,cnt=0;
for(int i=lst;i<=m;++i) {
int flag=0;
for(cnt+=det[i];!cnt&&p<=i;++p) {
a[m+p]=arr[p];
x=arr[p].u,y=arr[p].v;
if(find(x)==find(y)) {
split(x,y);
int pr=s[y].id;
int nx=s[pr].v;
if(s[y].si&1) {
++cnt,--det[a[nx].t];
}
if(a[nx].t<=m) {
vis[s[y].id-n]=0;
}
DEC(pr,a[nx].u);
DEC(pr,a[nx].v);
}
int now=++tot;
a[m+p].t=m+1;
s[now].v=m+p;
s[now].t=m+1;
pushup(now),ADD(now,x),ADD(now,y);
}
left[i]=p-1;
if(i+1<=m&&vis[i+1]) {
vis[i+1]=0;
int now=i+1+n;
DEC(now,arr[i+1].u);
DEC(now,arr[i+1].v);
}
}
for(int i=1;i<=Q;++i) {
scanf("%d%d",&x,&y);
if(y<lst) {
printf("YES
");
}
else {
if(x>left[y]) printf("YES
");
else printf("NO
");
}
}
return 0;
}