传送门
容易想到莫对+并查集乱搞,强制在线就分块+并查集乱搞,时空复杂度好像都不太行的样子。
我们维护一个类似并查集的树形结构,加入一条边i,若这条边的两端点已经联通,找到这个环上最早的一条边j,那么当询问区间左端点在i之前时,当且仅当右端点延伸到i之后,删掉j这条边并不改变区间的连通性(j~i不存在边可以替换j维持原有的连通性),直接在树上用当前边i替换边j,且记录下pr[i]=j。
查询时找到区间[l,r]内pr<l的边的数目,就是区间并查集中的边数,联通块数即n-边数。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
#define pi acos(-1.0)
const int N=200007*2;
typedef long long LL;
typedef double db;
using namespace std;
int n,m,q,type,pr[N],ex[N],ey[N];
template<typename T> void read(T &x) {
char ch=getchar(); T f=1; x=0;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
#define lc ch[x][0]
#define rc ch[x][1]
#define mid ((l+r)>>1)
struct lct{
int p[N],ch[N][2],mi[N],tot,flip[N];
int isroot(int x) { return (x!=ch[p[x]][0])&&(x!=ch[p[x]][1]); }
void upd(int x) {
mi[x]=x;
if(lc) mi[x]=min(mi[x],mi[lc]);
if(rc) mi[x]=min(mi[x],mi[rc]);
}
void down(int x) {
if(!flip[x]) return;
swap(lc,rc);
flip[lc]^=1;
flip[rc]^=1;
flip[x]^=1;
}
void rotate(int x) {
int y=p[x],z=p[y],l=(x==ch[y][1]),r=(l^1);
if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
ch[x][r]=y; p[y]=x;
upd(y); upd(x);
}
void splay(int x) {
static int sta[N],top,tp;
tp=x; sta[top=1]=tp;
for(;!isroot(tp);tp=p[tp]) sta[++top]=p[tp];
while(top) down(sta[top--]);
for(;!isroot(x);rotate(x)) {
int y=p[x],z=p[y];
if(!isroot(y)) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
}
}
void access(int x) {
for(int t=0;x;x=p[t=x]) {
splay(x);
rc=t;
upd(x);
}
}
void newroot(int x) {
access(x);
splay(x);
flip[x]^=1;
}
int find_root(int x) {
access(x);
splay(x);
while(lc) x=lc;
return x;
}
void lik(int x,int y) {
newroot(x);
splay(x); splay(y);
p[x]=y;
}
void cut(int x,int y) {
newroot(x);
access(y);
splay(y);
if(ch[y][0]==x) {
ch[y][0]=p[x]=0;
upd(y);
}
}
void lik(int x,int y,int i) {
if(find_root(x)==find_root(y)) {
newroot(x);
access(y);
splay(y); int z=mi[y];
pr[i]=z;
cut(z,ex[z]); cut(z,ey[z]);
}
lik(x,i); lik(i,y);
}
}L;
struct sgtree {
int rt[N],tot,ch[N*20][2],sg[N*20];
void upd(int &x,int last,int l,int r,int pos) {
x=++tot;
sg[x]=sg[last]+1;
lc=ch[last][0];
rc=ch[last][1];
if(l==r) return;
if(pos<=mid) upd(lc,ch[last][0],l,mid,pos);
else upd(rc,ch[last][1],mid+1,r,pos);
}
int qry(int x,int l,int r,int ql,int qr) {
if(!x) return 0;
if(l>=ql&&r<=qr) return sg[x];
if(qr<=mid) return qry(lc,l,mid,ql,qr);
if(ql>mid) return qry(rc,mid+1,r,ql,qr);
return qry(lc,l,mid,ql,qr)+qry(rc,mid+1,r,ql,qr);
}
}S;
int main() {
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
read(n); read(m); read(q); read(type);
For(i,1,n+m) L.upd(i);
For(i,1,m) {
int x,y;
read(x); read(y);
ex[i]=x+m; ey[i]=y+m;
if(x==y) pr[i]=m;
else L.lik(m+x,m+y,i);
}
For(i,1,m) S.upd(S.rt[i],S.rt[i-1],1,m+1,pr[i]+1);
int ans=0;
For(i,1,q) {
int l,r;
read(l); read(r);
if(type) { l^=ans; r^=ans; }
ans=S.qry(S.rt[r],1,m+1,1,l)-S.qry(S.rt[l-1],1,m+1,1,l);
ans=n-ans;
printf("%d\n",ans);
}
Formylove;
}