以前做这个题简直是噩梦的难度
有个很神的做法就是 利用最简联通形式来统计联通块
把一个要求的区间写成一颗等价的树,,就有了统一的标准
然后考虑怎么构造这棵树,看每次加入的边,如果已经联通,则考虑把这个环上最早加的边弹出,这样可以在区间往右移时保留尽量多的边。
然后记录哪一条边被这一条边顶替
查询时对于一个区间,默认这个区间没有联通块 如果区间内弹出了区间内的边,则这一定是重复的边,和区间里的另一条边等价,就忽略这一条边
如果弹出了区间外的边,则在这个区间里这个边一定链接了两个联通块,联通块个数--
如果没有弹出边,则这一条边不与1~r的边矛盾,更不与l~r的边矛盾,所以联通块个数--
这样就可以用lct求出替代数组,用主席树求区间<l的数的个数,n-查询结果即是答案
注:
1、access不要忘了splay
2、边化为点时-n和两边link cut
3、查询和修改都在一颗主席树上时,注意区分赋值语句
4、主席树没有up
5、注意改用什么变量
码(1A(主席树+lct)的壮举):
#include<iostream>
#include<cstdio>
using namespace std;
#define N 200005
int v[N*40],op,tot,rt[N],ch2[N*40][2],ch[N<<1][2],ntr[N],q[N],z[N],a,b,c,lll,rrr,minn[N<<1],from[N<<1],val[N<<1],rev[N<<1],fu[N<<1],ans,i,j,n,m,k,type;
void gai(int last,int o,int l,int r)
{
if(op==0) v[o]=v[last]+1;
if(a<=l&&r<=b)
{
if(op==1)
{
c+=v[o]-v[last];
}
return ;
}
int mid=(l+r)>>1;
if(op==0)ch2[o][0]=ch2[last][0];
if(op==0)ch2[o][1]=ch2[last][1];
if(a<=mid)
{
if(op==0) ch2[o][0]=++tot;
gai(ch2[last][0],ch2[o][0],l,mid);
}
if(b>mid)
{
if(op==0) ch2[o][1]=++tot;
gai(ch2[last][1],ch2[o][1],mid+1,r);
}
}
void up(int o)
{
minn[o]=val[o];
from[o]=o;
if(ch[o][0]>0&&minn[ch[o][0]]<minn[o])
{
minn[o]=minn[ch[o][0]];
from[o]=from[ch[o][0]];
}
if(ch[o][1]>0&&minn[ch[o][1]]<minn[o])
{
minn[o]=minn[ch[o][1]];
from[o]=from[ch[o][1]];
}
}
void down(int o)
{
if(rev[o])
{
rev[o]^=1;
rev[ch[o][0]]^=1;
rev[ch[o][1]]^=1;
swap(ch[o][0],ch[o][1]);
}
}
void set(int o,int wh,int child)
{
ch[o][wh]=child;
fu[child]=o;
up(o);
}
int getwh(int o)
{
return ch[fu[o]][0]==o?0:1;
}
bool isrt(int o)
{
if(fu[o]==0)return 1;
if(ch[fu[o]][0]==o||ch[fu[o]][1]==o)return 0;
return 1;
}
void rotate(int o)
{
int fa=fu[o];
int ye=fu[fa];
int wh=getwh(o);
bool ysg=0;
if(isrt(fa)==1)ysg=1;
set(fa,wh,ch[o][wh^1]);
set(o,wh^1,fa);
fu[o]=ye;
if(ysg==0)
ch[ye][ch[ye][0]==fa?0:1]=o;
}
int sta[N];
void splay(int o)
{
int top=0,i=o;sta[++top]=o;
for(;isrt(i)==0;i=fu[i])
{
sta[++top]=fu[i];
}
for(i=top;i>=1;i--)down(sta[i]);
for(;isrt(o)==0;rotate(o))
if(isrt(fu[o])==0)
getwh(o)==getwh(fu[o])?rotate(fu[o]):rotate(o);
}
void access(int o)
{
int last=0;
for(;o!=0;last=o,o=fu[o])
{
splay(o);
ch[o][1]=last;
up(o);
}
}
void huan(int o)
{
access(o);
splay(o);
rev[o]^=1;
}
void link(int a,int b)
{
huan(a);
fu[a]=b;
access(a);
}
void cut(int a,int b)
{
huan(a);
access(b);
splay(b);
ch[b][0]=fu[a]=0;
}
int main()
{
//注意初值!!!
scanf("%d%d%d%d",&n,&m,&k,&type);
for(i=1;i<=n;i++)val[i]=9999999;
for(i=1;i<=m;i++)
{
val[i+n]=i;
scanf("%d%d",&a,&b);
q[i]=a;z[i]=b;
if(a!=b)
{
access(a);
splay(a);
int l1=a,l2=b;
while(ch[l1][0]!=0)l1=ch[l1][0];
access(b);
splay(b);
while(ch[l2][0]!=0)l2=ch[l2][0];
if(l1==l2)
{
huan(a);
access(b);
splay(b);
ntr[i]=from[b]-n;
int l3=from[b];
cut(q[l3-n],l3);
cut(l3,z[l3-n]);
link(a,i+n);
link(b,i+n);
}else
{
link(a,i+n);
link(b,i+n);
}
}else ntr[i]=m;
a=ntr[i]+1;b=ntr[i]+1;
rt[i]=++tot;
gai(rt[i-1],rt[i],1,m+1);
}
op=1;
for(i=1;i<=k;i++)
{
scanf("%d%d",&lll,&rrr);
if(type==1)lll^=ans,rrr^=ans;
c=0;a=1,b=lll;
gai(rt[lll-1],rt[rrr],1,m+1);
ans=n-c;
printf("%d\n",ans);
}
}