树链剖分学习笔记
2022/4/28 23:12:39
本文主要是介绍树链剖分学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
树链剖(pōu)分
定义
树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。
树链剖分有多种形式,如重链剖分、长链剖分等,通常说的树链剖分指重链剖分。
重链剖分
首先给出一些定义:
-
重子节点:所有子节点中子树大小最大的子节点
-
轻子节点:除重子节点的其它子节点
-
重边:从这个节点连到重子节点的边
-
轻边:从这个节点到其它子节点的边
-
重链:将若干条重边相连得到的链
(图源:oi-wiki)
跑两个 dfs ,第一个跑出来子树大小,深度,父节点和重子节点,第二个 dfs 优先扩展重子节点,记录新编号和新点权,这样能保证先剖出来的一定是重链。
int hson[MAXN], // 重子节点 fa[MAXN], // 父节点 cnt[MAXN], // 子树大小 dep[MAXN], // 深度 val[MAXN], // val[i]表示初始编号i的点的点权 top[MAXN], // 所在链的顶 id[MAXN], // 新编号(dfn序) a[MAXN]; // 新编号为i的点的点权 void dfs(int u,int f) { cnt[u]=1; for(auto son:Tree[u]) { if(son==f) continue; dep[son]=dep[u]+1;fa[son]=u; dfs(son,u);cnt[u]+=cnt[son]; if(cnt[son]>cnt[hson[u]]) hson[u]=son; } } void dfs1(int u,int f,int t) { id[u]=++tot;a[tot]=val[u];top[u]=t; if(hson[u]) dfs1(hson[u],u,t); for(auto son:Tree[u]) if(son!=hson[u]&&son!=f) dfs1(son,u,son); }
重链剖分的性质
-
树上每个节点属于且仅属于一条重链
-
若 \((u,v)\) 是一条轻边,那么 \(size(v)<size(u)/2\)。
-
从根结点到任意结点的路所经过的轻重链的个数必定都小于 \(\log_2n\)。
因此,每向下走一条轻边时,子树大小都至少会除以 \(2\),所以对于树上任意一条路径最多会经过 \(\log_2n\) 条重链。
- 子树中的 \(id\) ,也就是 \(dfn\) ,一定是连续的。
一些简单操作
LCA
每次把重链顶深度较大的点向上跳重链,如果两个点在同一条链上,就直接返回深度更小的。时间复杂度 \(O(\log_2n)\)。
int lca(int x,int y) { int fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y); x=fa[fx],fx=top[x]; } if(dep[x]>dep[y]) swap(x,y); return x; }
路径上的点权修改
过程和求 LCA 类似,由于每一条重链上的 dfn 值都是连续的,可以用线段树修改,在向上跳的过程中把每条重链都修改了,最后修改剩余部分。时间复杂度 \(O(\log_2^2n)\)。
void update_chain(int x,int y,int k) { int fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y); update(1,1,tot,id[fx],id[x],k); x=fa[fx],fx=top[x]; } if(id[x]>id[y]) swap(x,y); update(1,1,tot,id[x],id[y],k); }
路径上的点权和查询
在向上跳的时候答案加上每条重链的和,最后加上剩余部分。
int query_chain(int x,int y) { int res=0,fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y); res+=query(1,1,tot,id[fx],id[x]); x=fa[fx],fx=top[x]; } if(id[x]>id[y]) swap(x,y); res+=query(1,1,tot,id[x],id[y]); return res%mod; }
例题
CF593D Happy Tree Party
题面传送门
题解传送门
CF916E Jamie and Tree
题面传送门
题解传送门
这篇关于树链剖分学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-15JavaMailSender是什么,怎么使用?-icode9专业技术文章分享
- 2024-11-15JWT 用户校验学习:从入门到实践
- 2024-11-15Nest学习:新手入门全面指南
- 2024-11-15RestfulAPI学习:新手入门指南
- 2024-11-15Server Component学习:入门教程与实践指南
- 2024-11-15动态路由入门:新手必读指南
- 2024-11-15JWT 用户校验入门:轻松掌握JWT认证基础
- 2024-11-15Nest后端开发入门指南
- 2024-11-15Nest后端开发入门教程
- 2024-11-15RestfulAPI入门:新手快速上手指南