之前没怎么打过LCT,这次来苏州集训乘机补一个坑
LCT功能十分强大,它可以维护一个森林的一系列问题
一句话来说,就是对于森林里的每棵树做轻重链剖分,每条重链用splay维护
这是LCT最关键的操作
access(x)是把x弄到与根在同一个splay上的操作,也就是把x到根的虚边全部变实边过程大概是:
上代码:
void access(int x)
{
for(int t=0; x; t=x,x=fa[x])
{
splay(x),ch[x][1]=t,update(x);
if(t) fa[t]=x;
}
}
功能是把x变成根,并令x没有右儿子
显然,可以用access和splay实现
void makeroot(int x)
{
access(x); splay(x); rev[x]^=1;//这个操作之后LCT新根到原根的链需要翻转
}
连接x和y
void link(int x,int y)
{
makeroot(x); fa[x]=y;//连一条虚边
}
如果题目不保证这是一棵森林,需要判断y所在的splay是不是根
断开x和y之间的边
void cut(int x,int y)
{
makeroot(x); access(y); splay(y); ch[y][0]=fa[x]=0; update(y);
}
思路很简单,每个点向i+v[i]连边,如果i+v[i]大于n则连向弹飞点,修改先做一次cut后link,询问就makeroot(x),access(n+1),splay(n+1),然后就看这颗平衡树的大小
#include
using namespace std;
const int N=3e5+77;
int ch[N][2],fa[N],rev[N],Q[N],top,siz[N],n,q,a[N];
bool isroot(int x)
{
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
bool get(int x)
{
return ch[fa[x]][1]==x;
}
void update(int x)
{
siz[x]=1;
if(ch[x][0]) siz[x]+=siz[ch[x][0]];
if(ch[x][1]) siz[x]+=siz[ch[x][1]];
}
void pushdown(int x)
{
if(!rev[x]) return;
rev[ch[x][0]]^=1; rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]=0;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],l=get(x),r=l^1;
if(!isroot(y)) ch[z][get(y)]=x;
fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r]; ch[x][r]=y;
update(x); update(y);
}
void splay(int x)
{
top=0;
Q[++top]=x;
for(int i=x; !isroot(i); i=fa[i]) Q[++top]=fa[i];
while(top) pushdown(Q[top--]);
while(!isroot(x))
{
int y=fa[x],z=fa[y],d1=ch[y][1]==x,d2=ch[z][1]==y;
if(!isroot(y))
{
if(d1==d2) rotate(y),rotate(x); else rotate(x),rotate(x);
}
else rotate(x);
}
update(x);
}
void access(int x)
{
for(int t=0; x; t=x,x=fa[x])
{
splay(x),ch[x][1]=t,update(x);
if(t) fa[t]=x;
}
}
void makeroot(int x)
{
access(x); splay(x); rev[x]^=1;
}
void link(int x,int y)
{
makeroot(x); fa[x]=y;
}
void cut(int x,int y)
{
makeroot(x); access(y); splay(y); ch[y][0]=fa[x]=0; update(y);
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n+1; i++) siz[i]=1;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
if(i+a[i]>n) link(i,n+1);else link(i,a[i]+i);
}
scanf("%d",&q);
while(q--)
{
int op;
scanf("%d",&op);
if(op==1)
{
int x; scanf("%d",&x); x++;
makeroot(x),access(n+1),splay(n+1);
printf("%d\n",siz[n+1]-1);
}
else
{
int x,y;
scanf("%d%d",&x,&y); x++;
cut(x,min(n+1,x+a[x])); link(x,min(x+y,n+1));
a[x]=y;
}
}
}