【学习笔记】动态树 Link Cut Tree
算法简介
动态树(Link Cut Tree)简称lct,可以维护动态的联通结构和动态链上信息维护问题,高妙数据结构。
算法流程
talk is cheap,show me the code.
洛谷模板题代码。
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=100010;
struct Link_Cut_Tree{
int sum[N],ans[N],son[N][2],fa[N],p[N];
bool tag[N];
inline void pushdown(int u){
if(!tag[u])return ;
tag[son[u][0]]^=1,tag[son[u][1]]^=1;
swap(son[u][0],son[u][1]),tag[u]=0;
return ;
}
inline void update(int u){
ans[u]=sum[u]^ans[son[u][0]]^ans[son[u][1]];
return ;
}
inline bool isroot(int u){return !(son[fa[u]][0]==u||son[fa[u]][1]==u);}
inline void rotate(int u){
int x=fa[u],k=(son[x][1]==u);fa[u]=fa[x];
if(fa[x]&&!isroot(x))son[fa[x]][son[fa[x]][1]==x]=u;
son[x][k]=son[u][k^1],fa[son[u][k^1]]=x,update(x);
son[u][k^1]=x,fa[x]=u,update(u);
return ;
}
inline void splay(int u){
update(u);
int top=0;
for(int i=u;;i=fa[i]){
p[++top]=i;
if(isroot(i))break;
}
for(int i=top;i>=1;i--)pushdown(p[i]);
while(!isroot(u)){
int x=fa[u];
if(!isroot(x)){
if((son[fa[x]][0]==x)^(son[x][0]==u))rotate(u);
else rotate(x);
}rotate(u);
}
return ;
}
inline void access(int u){
int fir=u;
for(int x=0;u;x=u,u=fa[u])splay(u),son[u][1]=x,update(u);
splay(fir);
return ;
}
inline void makeroot(int u){
access(u),splay(u),tag[u]^=1;
return ;
}
inline void split(int x,int y){
makeroot(x),access(y),splay(y);
return ;
}
inline int findroot(int u){
access(u);
while(son[u][0])u=son[u][0];
splay(u);
return u;
}
inline void cut(int x,int y){
if((findroot(x)!=findroot(y)))return ;
makeroot(x),access(y),splay(y);
if(son[y][0]==x&&!son[x][1])fa[x]=son[y][0]=0,update(y);
return ;
}
}G;
int n,m;
signed main(){
n=rd(),m=rd();
for(int i=1;i<=n;i++)G.sum[i]=G.ans[i]=rd();
for(int i=1;i<=m;i++){
int k=rd(),x=rd(),y=rd();
if(k==0)G.split(x,y),printf("%d\n",G.ans[y]);
else if(k==1){
G.makeroot(y);
if(G.findroot(x)==y)continue;
G.fa[y]=x;
}
else if(k==2)G.cut(x,y);
else if(k==3)G.splay(x),G.sum[x]=y,G.update(x);
}
return 0;
}
lct的换根操作是通过splay的结构实现的,需要将u转到根后将整颗splay翻转。
同时由于lct的复杂度基于玄学的splay,如果splay少了可能会T,多转几下。(如findroot中的splay)
应用
挂个链接
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】