【持续更新】LCT学习笔记

前言

之前没怎么打过LCT,这次来苏州集训乘机补一个坑
LCT功能十分强大,它可以维护一个森林的一系列问题

LCT的结构

一句话来说,就是对于森林里的每棵树做轻重链剖分,每条重链用splay维护

LCT基本操作

Access

这是LCT最关键的操作

access(x)是把x弄到与根在同一个splay上的操作,也就是把x到根的虚边全部变实边过程大概是:

  1. 将x splay到x所属平衡树的根
  2. 令x的右儿子为x’(初始x’=NULL)这相当于把虚边边实边
  3. 令x’=x x=fa[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;
	}
}

makeroot

功能是把x变成根,并令x没有右儿子
显然,可以用access和splay实现

void makeroot(int x)
{
	access(x); splay(x); rev[x]^=1;//这个操作之后LCT新根到原根的链需要翻转
}

link

连接x和y

void link(int x,int y)
{
	makeroot(x); fa[x]=y;//连一条虚边
}

如果题目不保证这是一棵森林,需要判断y所在的splay是不是根

cut

断开x和y之间的边

void cut(int x,int y)
{
	makeroot(x); access(y); splay(y); ch[y][0]=fa[x]=0; update(y);
}

例题

[HNOI2010]弹飞绵羊

思路很简单,每个点向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;
		}
	}
}

你可能感兴趣的:(【持续更新】LCT学习笔记)