正题
先放一篇很好的LCT总结:https://www.cnblogs.com/flashhu/p/8324551.html
看这个就够了,讲得非常好,在这里我就不多说了。
说几个要点,学会可以帮助更好的理解LCT:
1.若给出的是一棵有根树,那么就不能makeroot这种操作。
2.其次,若要找两个点的lca,我们可以access(x),再access(y),然后找x所在splay的父亲即可。特判在一条链上的情况
3.实际上LCT能维护的不过也就是子树信息,路径信息,子树信息可以看做是把一个点splay后去除左儿子的信息
4.路径信息就直接split(x,y),如果不支持换根或者不支持改变边的状态,考虑树上差分。
在今后刷LCT的时候遇到有趣的事情或者解法,会补blog。
体表粘一下xzy神的。(貌似前面一大片题都可以用树剖搞定,不过显然LCT代码又短,跑起来又快)
- P2147 [SDOI2008]Cave 洞穴勘测
- P3690 【模板】Link Cut Tree
- P3203 [HNOI2010]弹飞绵羊
- P2173 [ZJOI2012]网络
- P1501 [国家集训队]Tree II
- P4172 [WC2006]水管局长
- [Luogu/POJ3522]最小差值生成树
- P2387 [NOI2014]魔法森林
- [HDU5398] GCD Tree
- [BZOJ4736]温暖会指引我们前行
- P1505 [国家集训队]旅游
- P2542 [AHOI2005]航线规划
- P2486 [SDOI2011]染色
- P4180 [Beijing2010组队]次小生成树Tree
- [BZOJ4998]星球联盟
- [BZOJ2959]长跑
- [BJOI2014]大融合
- [UOJ207]共价大爷游长沙
- [COGS2701]动态树
- [BZOJ3626][LNOI2014]LCA
- [THUWC 2017]在美妙的数学王国中畅游
- [AH2017/HNOI2017]单旋
- [BZOJ3514]Codechef MARCH14 GERALD07加强版
- [SDOI2017]树点涂色
- [luogu3613]睡觉困难综合征
- [ZJOI2016]大森林
- [ZJOI2018]历史
- Qtree1
- Qtree2
- Qtree3
- Qtree4
- Qtree5
- Qtree6
- Qtree7
最后粘一粘模板:
#include<bits/stdc++.h>
#define ls son[x][0]
#define rs son[x][1]
using namespace std;
const int N=100010;
int sum[N],val[N],son[N][2],fa[N],n,m,type,x,y;
int sta[N],top=0;
bool rev[N];
bool isroot(int x){
return son[fa[x]][0]!=x && son[fa[x]][1]!=x;
}
void pushdown(int x){
if(!rev[x]) return ;
rev[x]=false;
rev[ls]^=true;rev[rs]^=true;
swap(son[ls][0],son[ls][1]);
swap(son[rs][0],son[rs][1]);
}
void update(int x){
sum[x]=sum[ls]^sum[rs]^val[x];
}
void rotate(int x){
int f=fa[x],ff=fa[f],w=0;
if(son[f][0]==x) w=1;
else w=0;
if(!isroot(f)){
if(son[ff][0]==f) son[ff][0]=x;
else son[ff][1]=x;
}fa[x]=ff;
son[f][1-w]=son[x][w];
if(son[x][w]) fa[son[x][w]]=f;
fa[f]=x;son[x][w]=f;
update(f);update(x);
}
void splay(int x){
sta[top=1]=x;for(int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
for(int i=top;i>=1;i--) pushdown(sta[i]);
while(!isroot(x)){
if(!isroot(fa[x])){
if((son[fa[x]][0]==x) ^ (son[fa[fa[x]]][0]==fa[x])) rotate(x);
else rotate(fa[x]);
}
rotate(x);
}
}
void access(int x){
for(int last=0;x;last=x,x=fa[x]) splay(x),son[x][1]=last,update(x);
}
void makeroot(int x){
access(x);splay(x);rev[x]^=1;swap(son[x][0],son[x][1]);
}
int findroot(int x){
access(x);splay(x);
while(son[x][0]) pushdown(x),x=son[x][0];
return x;
}
void split(int x,int y){
makeroot(x);access(y);splay(y);
}
void link(int x,int y){
split(x,y);
if(findroot(y)==x) return ;
fa[x]=y;
}
void solve(int x,int y){
split(x,y);
printf("%d\n",sum[y]);
}
void cut(int x,int y){
split(x,y);
if(findroot(y)!=x || fa[x]!=y || son[x][1]) return ;
fa[x]=son[y][0]=0;
update(y);
}
void change(int x,int y){
access(x);splay(x);val[x]=y;update(x);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&val[i]),sum[i]=val[i];
while(m--){
scanf("%d %d %d",&type,&x,&y);
if(type==0) solve(x,y);
if(type==1) link(x,y);
if(type==2) cut(x,y);
if(type==3) change(x,y);
}
}
本文深入解析了LCT算法的关键概念与操作,如makeroot、access和split,并通过多个实战题目帮助读者掌握LCT在子树信息、路径信息处理上的应用。文章附带了详细的LCT模板代码,适合算法竞赛选手和数据结构爱好者学习。
2656

被折叠的 条评论
为什么被折叠?



