题面:
有 n n n 个点,有一个长度为 m m m 的边序列 A A A, q q q 次询问由这 n n n 个点和 A l , ⋯ , A r A_l,\cdots,A_r Al,⋯,Ar 的边构成的图中的连通块数量。强制在线。
n , q ≤ 1 0 5 n,q\leq 10^5 n,q≤105, m ≤ 2 × 1 0 5 m\leq 2\times 10^5 m≤2×105。
题解:
在线也能把它搞成离线:枚举右端点 r r r 右移,并维护 A 1 , ⋯ , A r A_1,\cdots,A_r A1,⋯,Ar 组成的以下标为边权的最大生成森林,以及一棵可持久化线段树维护每条边是否在生成树内。
然后询问的时候我们直接在可持久化线段树上问 A 1 , ⋯ , A r A_1,\cdots,A_r A1,⋯,Ar 组成的最大生成森林中有多少条边编号在 [ l , r ] [l,r] [l,r] 内,即可得到 A l , ⋯ , A r A_l,\cdots,A_r Al,⋯,Ar 的生成森林中边的数量。然后用点减边即可得到连通块数。
时间复杂度 O ( ( m + q ) log m ) O((m+q)\log m) O((m+q)logm)。
#include<bits/stdc++.h>
#define N 1000010
#define M 2000010
#define INF 0x7fffffff
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
struct edge
{
int u,l,r;
}e[M];
int n,m,q,rt[M];
bool t;
namespace Seg
{
#define lc(u) ch[u][0]
#define rc(u) ch[u][1]
const int NN=10000000;
int node,ch[NN][2],sum[NN];
int copy(int lst){node++,lc(node)=lc(lst),rc(node)=rc(lst),sum[node]=sum[lst];return node;}
void up(int u){sum[u]=sum[lc(u)]+sum[rc(u)];}
void update(int &u,int lst,int l,int r,int x)
{
u=copy(lst);
if(l==r) return (void)(sum[u]^=1);
int mid=(l+r)>>1;
if(x<=mid) update(lc(u),lc(lst),l,mid,x);
else update(rc(u),rc(lst),mid+1,r,x);
up(u);
}
int query(int u,int l,int r,int ql)
{
if(!u) return 0;
if(ql<=l) return sum[u];
int mid=(l+r)>>1,ans=0;
if(ql<=mid) ans+=query(lc(u),l,mid,ql);
return ans+query(rc(u),mid+1,r,ql);
}
#undef lc
#undef rc
}
namespace LCT
{
#define lc(u) t[u].ch[0]
#define rc(u) t[u].ch[1]
const int NN=N+M;
struct data
{
int val,pos;
data(){};
data(int _v,int _p){val=_v,pos=_p;}
};
bool operator < (const data &a,const data &b){return a.val<b.val;}
struct Tree
{
int fa,ch[2];
bool rev;
data val,sum;
}t[NN];
int node;
void up(int u){t[u].sum=min(t[u].val,min(t[lc(u)].sum,t[rc(u)].sum));}
int newnode(int v){++node,t[node].val=data(v,node),up(node);return node;}
void downn(int u){swap(lc(u),rc(u)),t[u].rev^=1;}
void down(int u){if(t[u].rev) downn(lc(u)),downn(rc(u)),t[u].rev=0;}
bool get(int u){return rc(t[u].fa)==u;}
bool notroot(int u){return lc(t[u].fa)==u||rc(t[u].fa)==u;}
void rotate(int u)
{
int fa=t[u].fa,gfa=t[fa].fa; bool d1=get(u);
if(notroot(fa)) t[gfa].ch[get(fa)]=u; t[u].fa=gfa;
t[t[fa].ch[d1]=t[u].ch[d1^1]].fa=fa;
t[t[u].ch[d1^1]=fa].fa=u; up(fa);
}
void splay(int u)
{
static int sta[NN];
int top=1,now=sta[top]=u;
while(notroot(now)) sta[++top]=now=t[now].fa;
while(top) down(sta[top]),top--;
while(notroot(u))
{
int fa=t[u].fa;
if(notroot(fa)) rotate((get(u)^get(fa))?u:fa);
rotate(u);
}
up(u);
}
void access(int u)
{
for(int y=0;u;y=u,u=t[u].fa)
splay(u),rc(u)=y,up(u);
}
void makeroot(int u)
{
access(u),splay(u),downn(u);
}
int findleft(int u)
{
while(1)
{
down(u);
if(!lc(u)) return u;
u=lc(u);
}
}
int findroot(int u)
{
access(u),splay(u);
int rt=findleft(u);
splay(rt); return rt;
}
data query(int u,int v)
{
makeroot(u);
if(findroot(v)!=u) return data(-1,114514);
return t[u].sum;
}
void link(int u,int v)
{
access(u),splay(u),makeroot(v);
t[rc(u)=v].fa=u,up(u);
}
void cut(int u,int v)
{
makeroot(v),makeroot(u);
rc(u)=t[v].fa=0,up(u);
}
int update(int u,int v,int tim)
{
rt[tim]=rt[tim-1];
int now=newnode(tim);
data ptim=query(u,v);
if(ptim.val==-1)
{
link(u,now),link(now,v);
Seg::update(rt[tim],rt[tim],1,m,tim);
}
else if(tim>ptim.val)
{
int id=ptim.pos-n;
cut(e[id].l,e[id].u),cut(e[id].u,e[id].r);
link(u,now),link(now,v);
Seg::update(rt[tim],rt[tim],1,m,id);
Seg::update(rt[tim],rt[tim],1,m,tim);
}
return now;
}
#undef lc
#undef rc
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
n=LCT::node=read(),m=read(),q=read(),t=read();
for(int i=0;i<=n;i++) LCT::t[i].val=LCT::t[i].sum=LCT::data(INF,114514);
for(int i=1;i<=m;i++)
{
e[i].l=read(),e[i].r=read();
e[i].u=LCT::update(e[i].l,e[i].r,i);
}
int lans=0;
while(q--)
{
int l=read(),r=read();
if(t>0) l=(l+t*lans)%m+1,r=(r+t*lans)%m+1;
if(l>r) swap(l,r);
printf("%d\n",lans=(n-Seg::query(rt[r],1,m,l)));
}
return 0;
}
/*
3 3 3 0
1 2
2 3
1 3
1 1
2 2
2 3
*/
/*
4 5 114514 0
1 2
2 3
3 4
1 3
2 4
*/
/*
4 3 114514 0
1 2
2 3
3 4
*/