【数据结构】动态树
【数据结构】动态树
动态树(Link-Cut Tree),是OI中一种高级的数据结构,用于维护一个动态森林上的链上问题。性价比较高。
题目描述
给定
操作有四种,操作从
0 x y
代表询问从 到 的路径上的点的权值的 和。保证 到 是联通的。1 x y
代表连接 到 ,若 到 已经联通则无需连接。2 x y
代表删除边 ,不保证边 存在。3 x y
代表将点 上的权值变成 。
这是链上维护
我们用
接下来介绍一些核心操作:
access
将一个点与到它这颗子树的根的道路打通。我们沿着
inline void access(int x)
{
for(int rc = 0;x;rc = x,x = t[x].fa)
splay(x),t[x].son[1] = rc,update(x);
}
findroot
找到
inline int findroot(int x)
{
access(x);splay(x);
while(t[x].son[0]) pushdown(x),x = t[x].son[0];
splay(x);
return x;
}
makeroot
让
inline void makeroot(int x)
{
access(x);splay(x);rever(x);
}
link
连接
inline void link(int x,int y)
{
makeroot(x);
if(findroot(y) == x) return;
t[x].fa = y;
}
cut
切断
inline void cut(int x,int y)
{
makeroot(x);
if(findroot(y) != x || t[y].fa != x || t[y].son[0] != 0) return;
t[y].fa = 0;t[x].son[1] = 0;
update(x);
}
split
将
inline void split(int x,int y)
{
makeroot(x);access(y);splay(y);
}
综合下来,这道题就实现了。这只是LCT最基本的实现,更高级的应用还参考一些练习题。
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
struct LCT{
int fa,son[2],val,sum,tag;
}t[N];
inline int which(int x){return x == t[t[x].fa].son[1];}
inline void update(int x){t[x].sum = t[t[x].son[0]].sum ^ t[t[x].son[1]].sum ^ t[x].val;}
inline void rever(int x){if(!x) return; swap(t[x].son[0],t[x].son[1]);t[x].tag ^= 1;}
inline void pushdown(int x){if(t[x].tag) rever(t[x].son[0]),rever(t[x].son[1]); t[x].tag = 0;}
inline bool isroot(int x){return t[t[x].fa].son[0] != x && t[t[x].fa].son[1] != x;}
inline void rorate(int x)
{
int dir = which(x),y = t[x].fa,z = t[y].fa;
if(t[x].son[dir ^ 1]) t[t[x].son[dir ^ 1]].fa = y;
t[y].son[dir] = t[x].son[dir ^ 1];
t[x].fa = z;
if(!isroot(y)) t[z].son[which(y)] = x;
t[y].fa = x;
t[x].son[dir ^ 1] = y;
update(x);
update(y);
if(!isroot(y)) update(z);
}
inline void splay(int x)
{
int st[N],top = 0,now = x;
while(!isroot(now)) st[++top] = now,now = t[now].fa; st[++top] = now;
while(top) pushdown(st[top]),top--;
while(!isroot(x))
{
if(!isroot(t[x].fa))
rorate((which(x) ^ which(t[x].fa)) ? x : t[x].fa);
rorate(x);
}
update(x);
}
inline void access(int x)
{
for(int rc = 0;x;rc = x,x = t[x].fa)
splay(x),t[x].son[1] = rc,update(x);
}
inline int findroot(int x)
{
access(x);splay(x);
while(t[x].son[0]) pushdown(x),x = t[x].son[0];
splay(x);
return x;
}
inline void makeroot(int x)
{
access(x);splay(x);rever(x);
}
inline void link(int x,int y)
{
makeroot(x);
if(findroot(y) == x) return;
t[x].fa = y;
}
inline void cut(int x,int y)
{
makeroot(x);
if(findroot(y) != x || t[y].fa != x || t[y].son[0] != 0) return;
t[y].fa = 0;t[x].son[1] = 0;
update(x);
}
inline void split(int x,int y)
{
makeroot(x);access(y);splay(y);
}
inline int query(int x,int y)
{
split(x,y);return t[y].sum;
}
int main()
{
int n,m,op,x,y;
cin>>n>>m;
for(int i = 1;i <= n;i++) cin>>t[i].val;
for(int i = 1;i <= m;i++)
{
cin>>op>>x>>y;
if(op == 0) cout<<query(x,y)<<endl;
else if(op == 1) link(x,y);
else if(op == 2) cut(x,y);
else if(op == 3) splay(x),t[x].val = y;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通