线段树合并与分裂
合并 的时间复杂度证明
——引自《算法竞赛进阶指南》
一开始有 \(m\) 棵树,只有一个位置有权值,所以一棵树上结点数量为 \(O(\log n)\),\(m\) 棵树的结点总数也就是 \(O(m \log n)\)。
分析上面的代码,发现每一次进入 merge 函数,要么停止递归,要么继续递归并有一个点被垃圾回收。显然停止递归的 merge 次数与继续递归的 merge 次数同阶(不继续递归的情况是从递归的情况出来的,不会超过其两倍的数量)。
因此整个过程的复杂度就等于继续递归的 merge 函数进入次数的复杂度(每一次执行 merge 在不考虑递归时复杂度 \(O(1)\)),也就等同于被删除的结点个数,是不超过 \(O(m \log n)\) 的(有点像势能分析?)。
注意复杂度本身和是否回收结点没有关系,只是借以分析而已。
所以整个过程的复杂度也就是 \(O(m \log n)\)。
——引自 @ix35 的博客
有分裂操作的时间复杂度:每次分裂至多增加 \(\log n\) 个节点,故此最多存在 \(2m\log n\) 个节点,同理可均摊得时间复杂度。
本质
线段树的合并与分裂多半是在权值线段树合并上进行的。因此,合并与分裂在题目当中,大多是用来 快速合并、分裂若干有序序列的。
反比同样支持合并操作的 FHQ_Treap,它只能合并大小关系绝对确定的两棵树。
比如,序列 1,3,5,7
和 2,4,6,8
合并时,线段树合并得到的结果是 1,2,3,4,5,6,7,8
,而 FHQ_Treap 得到的结果为 1,3,5,7,2,4,6,8
。
-
P2824 [HEOI2016/TJOI2016] 排序:把每个有序块都看作一棵线段树,时间复杂度容易用势能分析证明。这道题正完美体现了上面所提“快速合并、分裂若干有序序列”。另外,这道题的另一种二分答案做法,告诉我们:二分答案的单调性并不一定很明显,有的时候要敢于进行尝试。