題目大意
給定一個圖,求編號在[l,r]之間的邊形成的圖的連通塊個數。
思路
考慮一條邊什麼時候會造成貢獻,即這條邊相連的兩個部分在之前從未連通過,或者是把所有編號小於l的邊去掉之後這兩個部分未連通。
對於第一種情況可以輕鬆地用並查集來實現。
對於第二種情況,對於每一個l,我們需要判斷出u,v這兩個點的所有路徑中是否存在一條路徑使得min(id)>=l,如果不存在則(u,v)這條邊可以造成一次貢獻,不難發現我們只需要處理出加入(u,v)這條邊時以編號爲權值的最大生成樹,環上最小的那條邊的編號即是否造成貢獻的臨界點,假設環上最小的邊的編號爲x,如果l<=x那麼無論如何都可以連通,否則總有一條邊不在[l,r]之間。
上述算法可以輕鬆地用lct+主席樹來維護。
/*=======================================
* Author : ylsoi
* Time : 2019.3.31
* Problem : bzoj3514
* E-mail : [email protected]
* ====================================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj3514.in","r",stdin);
freopen("bzoj3514.out","w",stdout);
}
template<typename T>void read(T &_){
_=0; T f=1; char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
_*=f;
}
string proc(){
ifstream f("/proc/self/status");
return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
}
const int maxn=2e5+10;
const int inf=0x3f3f3f3f;
int n,m,q,ty;
int cnt_seg;
pii e[maxn];
struct lct{
#define lc ch[o][0]
#define rc ch[o][1]
int ch[maxn<<1][2],fa[maxn<<1],tg[maxn<<1];
int stk[maxn<<1],w[maxn<<1],mn[maxn<<1];
void pushup(int o){
mn[o]=w[o];
if(lc)mn[o]=min(mn[o],mn[lc]);
if(rc)mn[o]=min(mn[o],mn[rc]);
}
void pushdown(int o){
if(!tg[o])return;
if(lc)tg[lc]^=1;
if(rc)tg[rc]^=1;
tg[o]=0,swap(lc,rc);
}
int rel(int o){return ch[fa[o]][1]==o;}
int isrt(int o){return ch[fa[o]][0]!=o && ch[fa[o]][1]!=o;}
void rotate(int o){
int f=fa[o],r=rel(o);
fa[o]=fa[f]; if(!isrt(f))ch[fa[f]][rel(f)]=o;
fa[ch[o][r^1]]=f; ch[f][r]=ch[o][r^1];
fa[f]=o; ch[o][r^1]=f;
pushup(f),pushup(o);
}
void splay(int o){
int p=o,tp=0;
while(true){
stk[++tp]=p;
if(isrt(p))break;
p=fa[p];
}
DREP(i,tp,1)pushdown(stk[i]);
for(int f;!isrt(o);rotate(o))
if(!isrt(f=fa[o]))rotate(rel(o)==rel(f) ? f : o);
}
void access(int o){
for(int res=0;o;o=fa[o]){
splay(o),ch[o][1]=res,pushup(o),res=o;
}
}
void mkrt(int o){access(o),splay(o),tg[o]^=1;}
void split(int x,int y){mkrt(x),access(y),splay(y);}
void link(int x,int y){mkrt(x),fa[x]=y;}
void cut(int x,int y){split(x,y),ch[y][0]=0,fa[x]=0,pushup(y);}
int query(int x,int y){split(x,y);return mn[y];}
#undef lc
#undef rc
}T;
#define mid ((l+r)>>1)
struct node{
int lc,rc,sum;
}t[maxn*20];
int root[maxn];
void insert(int &o,int l,int r,int p){
int now=++cnt_seg;
t[now]=t[o],o=now,++t[o].sum;
if(l==r)return;
if(p<=mid)insert(t[o].lc,l,mid,p);
else insert(t[o].rc,mid+1,r,p);
}
int query(int o1,int o2,int l,int r,int L,int R){
int sum=t[o2].sum-t[o1].sum;
if(!sum || (L<=l && r<=R))return sum;
sum=0;
if(L<=mid)sum+=query(t[o1].lc,t[o2].lc,l,mid,L,R);
if(R>=mid+1)sum+=query(t[o1].rc,t[o2].rc,mid+1,r,L,R);
return sum;
}
#undef mid
int fa[maxn];
int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);}
int main(){
File();
read(n),read(m),read(q),read(ty);
REP(i,1,n)fa[i]=i;
REP(i,1,n)T.w[i]=T.mn[i]=inf;
int u,v;
REP(i,1,m){
read(u),read(v);
e[i]=mk(u,v);
T.w[i+n]=T.mn[i+n]=i;
root[i]=root[i-1];
if(u==v)continue;
else if(find(u)!=find(v)){
fa[find(u)]=find(v);
insert(root[i],0,m,0);
}
else{
int mn=T.query(u,v);
insert(root[i],0,m,mn);
T.cut(mn+n,e[mn].fi);
T.cut(mn+n,e[mn].se);
}
T.link(i+n,u);
T.link(i+n,v);
}
int las=0;
REP(i,1,q){
read(u),read(v);
if(ty)u^=las,v^=las;
las=n-query(root[u-1],root[v],0,m,0,u-1);
printf("%d\n",las);
}
return 0;
}