Description
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
(强制在线)
题解
LCT神题==
主席树只是辅助==然而并不会太敲。
这题神YY==水平太烂所以还是看了wulala的题解==
首先观察对答案的贡献。
当一条边和后面的边形成了环,那么它对答案的贡献是0。
不然就是-1咯==
所以每次加入一条边就把它能形成的环的最早的弹掉,弹不了就弹0。
LCT一发。
然后答案就是n剪掉l~r中弹出的边中小于l的个数。
主席树一发。
发现自己主席树简直弱渣。
还有LCT中rotateTM竟然敲错了==调了良久没调出来==
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int M=4e5+5;
int qid[M],st[M];
struct LCT{
int tr[M][2],fa[M],mi[M],q[M],rev[M],val[M],top;
inline bool is_root(int x){
return tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x;
}
inline void up(int x){
mi[x]=x;
if(val[mi[tr[x][0]]]<val[mi[x]])mi[x]=mi[tr[x][0]];
if(val[mi[tr[x][1]]]<val[mi[x]])mi[x]=mi[tr[x][1]];
}
inline void rotate(int x){
int y=fa[x],z=fa[y],r=tr[y][0]==x,l=r^1;
if(!is_root(y)){
if(tr[z][0]==y)tr[z][0]=x;
else tr[z][1]=x;
}
fa[x]=z,fa[y]=x,fa[tr[x][r]]=y;
tr[y][l]=tr[x][r],tr[x][r]=y;
up(y);
}
inline void down(int x){
if(!rev[x])return ;
rev[tr[x][0]]^=1,rev[tr[x][1]]^=1;
rev[x]=0;swap(tr[x][0],tr[x][1]);
}
void Splay(int x){
q[++top]=x;
for(int i=x;!is_root(i);i=fa[i])q[++top]=fa[i];
for(;top;)down(q[top--]);
for(;!is_root(x);){
int y=fa[x],z=fa[y];
if(!is_root(y)){
if(tr[z][0]==y^tr[y][0]==x)rotate(x);
else rotate(y);
}
rotate(x);
}
up(x);
}
inline void Access(int x){
for(int t=0;x;t=x,x=fa[x])
Splay(x),tr[x][1]=t,up(x);
}
inline void Make_root(int x){
Access(x);Splay(x);rev[x]^=1;
}
inline void Cut(int x,int y){
Make_root(x);Access(y);Splay(y);
fa[x]=tr[y][0]=0;
}
inline int query(int x,int y){
Make_root(x),Access(y),Splay(y);
return mi[y];
}
inline void Link(int x,int y){
Make_root(x);fa[x]=y;
}
inline int find(int x){
Access(x);Splay(x);
for(;tr[x][0];)x=tr[x][0];
return x;
}
}T;
struct Pre_Tree{
int tot,ls[M*20],rs[M*20],cnt[M*20];
inline Pre_Tree(){tot=0;}
void Insert(int l,int r,int ot,int &tid,const int x){
cnt[tid=++tot]=cnt[ot]+1;
if(l==r)return;
ls[tid]=ls[ot],rs[tid]=rs[ot];
int mid=l+r>>1;
if(x<=mid)Insert(l,mid,ls[ot],ls[tid],x);
else Insert(mid+1,r,rs[ot],rs[tid],x);
}
int query(int lt,int rt,int l,int r,int k){
if(r==k)return cnt[rt]-cnt[lt];
int mid=l+r>>1;
if(k<=mid)return query(ls[lt],ls[rt],l,mid,k);
return query(rs[lt],rs[rt],mid+1,r,k)+cnt[ls[rt]]-cnt[ls[lt]];
}
}PT;
inline void rd(int &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
int main(){
int n,m,q,t,u,v;
rd(n),rd(m),rd(q),rd(t);
int tot=n;
for(int i=0;i<=n;++i)T.mi[i]=i,T.val[i]=1<<30;
for(int i=1;i<=m;++i){
rd(u),rd(v);
if(u==v){st[i]=i;continue;}
if(T.find(u)==T.find(v)){
int t=T.query(u,v);
st[i]=T.val[t];
T.Cut(u,t),T.Cut(v,t);
}
T.mi[++tot]=tot,T.val[tot]=i;
T.Link(u,tot),T.Link(v,tot);
}
for(int i=1;i<=m;++i)
PT.Insert(0,m,qid[i-1],qid[i],st[i]);
for(int lastans=0;q--;){
rd(u),rd(v);
if(t)u^=lastans,v^=lastans;
printf("%d\n",lastans=n-PT.query(qid[u-1],qid[v],0,m,u-1));
}
return 0;
}