Description
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
Input
第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。
Output
K行每行一个整数代表该组询问的联通块个数。
Sample Input
3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
Sample Output
2
1
3
1
HINT
对于
100
%
100\%
100%的数据,
1
≤
N
,
M
,
K
≤
200000
1≤N,M,K≤200000
1≤N,M,K≤200000。
分析:
一种很暴力的想法就是把
[
l
,
r
]
[l,r]
[l,r]的生成树建出来。
我们可以把
[
1
,
r
]
[1,r]
[1,r]的生成树建出来,尽量使用编号大的边(可以理解为以编号为边权建最大生成树)。此时,
[
l
,
r
]
[l,r]
[l,r]生成树的连通块数目就是
[
1
,
r
]
[1,r]
[1,r]生成树的连通块数目加上这棵树里面编号在
[
1
,
l
−
1
]
[1,l-1]
[1,l−1]范围内的边数。
我们可以通过lct维护生成树维护
[
1
,
i
]
[1,i]
[1,i]的生成树,尽量使用后面的边替代前面的边,并记录下替换掉的边为编号,插入到一颗可持久化权值线段树中。
查询时就查询
t
r
e
e
[
r
]
tree[r]
tree[r]中
[
1
,
l
−
1
]
[1,l-1]
[1,l−1]的边数,用
l
−
1
l-1
l−1去减掉这个值就是当前树里面编号在
[
1
,
l
−
1
]
[1,l-1]
[1,l−1]范围内的边数。
代码:
/**************************************************************
Problem: 3514
User: liangzihao
Language: C++
Result: Accepted
Time:28928 ms
Memory:202888 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=2e5+7;
const int inf=0x3f3f3f3f;
using namespace std;
int n,m,T,type,x,y,ans,cnt;
int from[maxn],to[maxn],root[maxn],num[maxn],val[maxn*2];
struct rec{
int l,r,data;
}t[maxn*80];
struct LCT{
struct node{
int l,r,fa,data,id;
bool rev;
}t[maxn*2];
bool isroot(int x)
{
return (x!=t[t[x].fa].l) && (x!=t[t[x].fa].r);
}
void updata(int x)
{
int l=t[x].l,r=t[x].r;
if (t[l].data<t[r].data) t[x].data=t[l].data,t[x].id=t[l].id;
else t[x].data=t[r].data,t[x].id=t[r].id;
if (val[x]<t[x].data) t[x].data=val[x],t[x].id=x;
}
void remove(int x)
{
if (!isroot(x)) remove(t[x].fa);
if (t[x].rev)
{
t[x].rev^=1;
swap(t[x].l,t[x].r);
if (t[x].l) t[t[x].l].rev^=1;
if (t[x].r) t[t[x].r].rev^=1;
}
}
void rttr(int x)
{
int y=t[x].l;
t[x].l=t[y].r;
if (t[y].r) t[t[y].r].fa=x;
if (x==t[t[x].fa].l) t[t[x].fa].l=y;
else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
t[y].fa=t[x].fa;
t[x].fa=y;
t[y].r=x;
updata(x),updata(y);
}
void rttl(int x)
{
int y=t[x].r;
t[x].r=t[y].l;
if (t[y].l) t[t[y].l].fa=x;
if (x==t[t[x].fa].l) t[t[x].fa].l=y;
else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
t[y].fa=t[x].fa;
t[x].fa=y;
t[y].l=x;
updata(x),updata(y);
}
void splay(int x)
{
remove(x);
while (!isroot(x))
{
int p=t[x].fa,g=t[p].fa;
if (isroot(p))
{
if (x==t[p].l) rttr(p);
else rttl(p);
}
else
{
if (x==t[p].l)
{
if (p==t[g].l) rttr(p),rttr(g);
else rttr(p),rttl(g);
}
else
{
if (p==t[g].l) rttl(p),rttr(g);
else rttl(p),rttl(g);
}
}
}
}
void access(int x)
{
int y=0;
while (x)
{
splay(x);
t[x].r=y;
updata(x);
y=x,x=t[x].fa;
}
}
void makeroot(int x)
{
access(x);
splay(x);
t[x].rev^=1;
}
void link(int x,int y)
{
makeroot(x);
splay(x);
access(y);
splay(y);
t[x].fa=y;
}
void cut(int x,int y)
{
makeroot(x);
access(y);
splay(y);
t[y].l=0,t[x].fa=0;
updata(y);
}
int getroot(int x)
{
if (isroot(x)) return x;
return getroot(t[x].fa);
}
bool check(int x,int y)
{
makeroot(x);
access(y);
splay(y);
return getroot(x)==y;
}
}lct;
void ins(int &p,int q,int l,int r,int x,int k)
{
if (!p) p=++cnt;
t[p].data=t[q].data+k;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid) t[p].r=t[q].r,ins(t[p].l,t[q].l,l,mid,x,k);
else t[p].l=t[q].l,ins(t[p].r,t[q].r,mid+1,r,x,k);
}
int getsum(int p,int l,int r,int x,int y)
{
if (x>y) return 0;
if ((l==x) && (r==y)) return t[p].data;
int mid=(l+r)/2;
if (y<=mid) return getsum(t[p].l,l,mid,x,y);
else if (x>mid) return getsum(t[p].r,mid+1,r,x,y);
return getsum(t[p].l,l,mid,x,mid)+getsum(t[p].r,mid+1,r,mid+1,y);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&T,&type);
for (int i=1;i<=m;i++) scanf("%d%d",&from[i],&to[i]);
for (int i=0;i<=n+m;i++) lct.t[i].data=val[i]=inf;
num[0]=n;
for (int i=1;i<=m;i++)
{
num[i]=num[i-1];
if (from[i]==to[i])
{
ins(root[i],root[i-1],1,m,i,1);
continue;
}
if (lct.check(from[i],to[i]))
{
int d=lct.t[to[i]].id;
lct.cut(from[d-n],d);
lct.cut(d,to[d-n]);
ins(root[i],root[i-1],1,m,d-n,1);
num[i]++;
}
else root[i]=root[i-1];
if (!lct.check(from[i],to[i]))
{
val[i+n]=i;
lct.link(from[i],i+n);
lct.link(i+n,to[i]);
num[i]--;
}
}
ans=0;
for (int i=1;i<=T;i++)
{
scanf("%d%d",&x,&y);
x^=ans*type,y^=ans*type;
ans=num[y]+(x-1)-getsum(root[y],1,m,1,x-1);
printf("%d\n",ans);
}
}