题目要的连通块个数可以表示为点数\(-\)所有生成树上的边数.考虑这个生成树边数,我们维护编号最大生成树,按照编号加入边,然后如果加的时候会成环就把环上编号最小的边挤掉,并且当前的第\(i\)条边的前驱边\(pre_i\)为刚才被挤掉的第\(j\)条边,如果没有前驱边就是0
然后对于一个询问,我们只把使得联连通块个数减少的边放在生成树上,也就是如果区间\([l,r]\)中同时存在\(i\)和\(pre_i\),就不统计\(i\)的贡献,那么有贡献的边都会满足\(pre_i<l\le i\le r\),这个可以建出主席树后二维数点实现
#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double
using namespace std;
const int N=2e5+10,inf=1<<30;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int n,m,q,op,ans,e[N<<1][2];
int fa[N<<1],ch[N<<1][2],id[N<<1];
bool tg[N<<1];
bool nrt(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
void psup(int x){id[x]=min(x<=n?inf:x,min(id[ch[x][0]],id[ch[x][1]]));}
void rev(int x){if(x) tg[x]^=1,swap(ch[x][0],ch[x][1]);}
void psdn(int x){if(tg[x]) rev(ch[x][0]),rev(ch[x][1]),tg[x]=0;}
void ppush(int x)
{
if(nrt(x)) ppush(fa[x]);
psdn(x);
}
void rot(int x)
{
int y=fa[x],z=fa[y],ty=ch[y][1]==x,w=ch[x][!ty];
if(nrt(y)) ch[z][ch[z][1]==y]=x;
ch[x][!ty]=y,ch[y][ty]=w;
if(w) fa[w]=y;
fa[y]=x,fa[x]=z;
psup(y);
}
void spl(int x)
{
ppush(x);
while(nrt(x))
{
int y=fa[x],z=fa[y];
if(nrt(y)) ((ch[y][1]==x)^(ch[z][1]==y))?rot(x):rot(y);
rot(x);
}
psup(x);
}
void acs(int x)
{
for(int y=0;x;y=x,x=fa[x])
spl(x),ch[x][1]=y,psup(x);
}
void mkrt(int x){acs(x),spl(x),rev(x);}
void split(int x,int y){mkrt(x),acs(y),spl(y);}
int fdrt(int x)
{
acs(x),spl(x);
psdn(x);
while(ch[x][0]) x=ch[x][0],psdn(x);
return x;
}
void link(int i)
{
int x=e[i][0],y=e[i][1];
mkrt(x),mkrt(y);
fa[x]=fa[y]=i;
}
void cut(int i)
{
int x=e[i][0],y=e[i][1];
split(x,y);
spl(i);
ch[i][0]=ch[i][1]=fa[x]=fa[y]=0;
}
vector<int> pt[N];
vector<int>::iterator it;
int s[N*30],sn[N*30][2],rt[N],tt;
void inst(int o1,int o2,int x)
{
s[o1]=s[o2]+1;
int l=1,r=m;
while(l<r)
{
int mid=(l+r)>>1;
if(x<=mid)
{
sn[o1][0]=++tt,sn[o1][1]=sn[o2][1];
o1=sn[o1][0],o2=sn[o2][0];
r=mid;
}
else
{
sn[o1][0]=sn[o2][0],sn[o1][1]=++tt;
o1=sn[o1][1],o2=sn[o2][1];
l=mid+1;
}
s[o1]=s[o2]+1;
}
}
int quer(int o,int l,int r,int ll,int rr)
{
if(!s[o]||ll>rr) return 0;
if(ll<=l&&r<=rr) return s[o];
int an=0,mid=(l+r)>>1;
if(ll<=mid) an+=quer(sn[o][0],l,mid,ll,rr);
if(rr>mid) an+=quer(sn[o][1],mid+1,r,ll,rr);
return an;
}
int main()
{
n=rd(),m=rd(),q=rd(),op=rd();
id[0]=inf;
for(int i=1;i<=m;++i)
{
e[i+n][0]=rd(),e[i+n][1]=rd();
if(e[i+n][0]==e[i+n][1]) continue;
if(fdrt(e[i+n][0])==fdrt(e[i+n][1]))
{
split(e[i+n][0],e[i+n][1]);
int ii=id[e[i+n][1]];
pt[ii-n].push_back(i);
cut(ii);
}
else pt[0].push_back(i);
link(i+n);
}
for(int i=1;i<=m;++i)
{
rt[i]=rt[i-1];
for(it=pt[i-1].begin();it!=pt[i-1].end();++it)
{
int x=*it,las=rt[i];
inst(rt[i]=++tt,las,x);
}
}
while(q--)
{
int l=rd()^(ans*op),r=rd()^(ans*op);
ans=n-quer(rt[l],1,m,l,r);
printf("%d\n",ans);
}
return 0;
}