线段树 分裂、合并
约定
线段树的分裂合并默认是操作 动态开点值域线段树,用 \(V\) 表示线段树的值域,用 \(a\) 和 \(b\) 表示两颗较小的树(即分裂得到的两颗子树或需要合并的两棵树)的大小(值域线段树的大小定义为叶结点的数量),用 \(a_{1\sim k}\) 表示多棵较小的树的大小
线段树分裂
给定一个 \(x\),把值域为 \([1,V]\) 的线段树分裂为值域 \([1,x]\) 和 \((x,V]\) 的两棵树
单次分裂的时间复杂度为 \(O(\log V)\)
线段树合并
把两棵 值域相交 的线段树合并为一棵
单次时间复杂度 \(O(\min(a,b)\log V)\)
若合并多棵线段树,则总时间复杂度为 \(O(\sum a_i\log V)\),优于启发式合并的 \(O(\sum a_i\log\sum a_i\log V)\)
若值域不交,则时间复杂度为 \(O(\log V)\) 的,实现方式类似 \(\text{fhq treap}\) 的 \(\text{merge}\) 操作
例 1:P5327 [ZJOI2019] 语言
给定一棵 \(n\) 个结点的树和 \(m\) 条链,求有多少无序点对 \((u,v)\;(u\ne v)\),满足存在一条链同时包含两者,\(n,m\le10^5\)
考虑对于每个 \(u\) 求出包含它的合法点对数量,答案即为 \(n\) 个点对应数量之和除以 \(2\)
包含 \(u\) 的合法 \((u,v)\) 的数量为经过 \(u\) 的所有链的并的大小减一
若干条链的并即为包含所有端点的最小连通子树
包含 \(a_{1\sim k}\) 的最小连通子树的大小为 \(\frac12(\text{dis}(a_1,a_k)+\sum_{i=1}^{k-1} \text{dis}(a_i,a_{i+1}))\),其中 \(a_{1\sim k}\) 按 \(\text{dfn}\) 排序
\(\text{dfs}\) 给定树时,维护包含当前处理结点的所有链的端点的可重集
通过树上差分,问题转化为向集合中加入数、从集合中删除数、查询集合中相邻点的距离之和(假设集合按 \(\text{dfn}\) 排序,统计答案时要加上第一个和最后一个的距离并乘上系数)、合并集合(要将处理子树时的集合与处理其父亲时的集合合并)
这容易通过动态开点权值线段树实现,其中线段树的 \(p\) 下标存储 \(\text{dfn}\) 为 \(p\) 的点的出现次数,非叶结点存储相邻点距离之和(平衡树也可以,且其空间复杂度线性)
若使用 \(O(n\log n)-O(1)\) \(\text{lca}\),则可以做到 \(O(n\log n)\);若使用 \(O(n)-O(\log n)\) \(\text{lca}\),则可以做到 \(O(n\log^2 n)\)(假设 \(n,m\) 同级),空间复杂度 \(O(n\log n)\)
例 2:T158644 [QwQOI2020] III
给定一个长为 \(n\) 的排列,\(m\) 次操作,区间升序 / 降序排序,或查询某一位置的值,\(n,m\le10^5\)
考虑颜色段均摊,有序的子段为一个颜色段,每个子段建立一棵权值线段树
对于查询某一位置的操作,找到所在段后线段树上二分即可
对于区间排序的操作,则将两端的段分裂(由于每段内有序,因此分裂成两半等同于按给定值分裂),并将中间的所有段合并为一个新段
时间复杂度 \(O(n\log^2n)\)(假设 \(n,q\) 同阶),空间复杂度 \(O(n\log n)\)
参考
- \(\text{2024.12.13 EZDS.pdf\;\;\; by Luzhuoyuan}\)

浙公网安备 33010602011771号