线段树相关技巧的小小总结

木xx木大

2021-07-05 21:13:23

算法·理论

开始 NOI 前的总复习!近期可能会随机掉落一些类似的总结,时间关系可能不会写得很细,而且会省去一些严谨的证明

[5k+的“小小”总结].jpg

个人认为线段树和分块可以说是最常用、变化最多的数据结构了。这里先总结一下线段树吧。

列举的例题类型相似的将会被放在一起,同一类型的大致按难度排序。

Update:推荐阅读本文的修订版。因为已经发了洛谷日报,所以本文就不删了。

一、较复杂的 pushup 操作

线段树可以维护和、积、最值等满足结合律的区间运算。

这里总结几种常用且较复杂的信息

二、线段树维护线段/直线

即李超线段树。详见李超树学习笔记

三、线段树维护单调栈(前缀最值相关)

这部分讨论线段树如何维护前缀严格最大值相关信息。

以《楼房重建》为例,这题求的是前缀严格最大值的个数。

s 表示区间严格最大值的个数,mx 表示区间最大值,设 solve(ro,x) 表示 ro 所覆盖的区间中考虑前缀最大值 x 后的区间严格最大值个数

由于每次只往一边递归,所以这个 solve 函数的复杂度是 O(\log n) 的。合并两个区间时,s_{ro}=s_{ls}+solve(rs,mx_{ls}),修改时会调用 O(\log n)solve 函数,单次修改的复杂度为 O(\log^2n)

但有时我们维护的信息不具有可减性(如取 \max,\min 等),为了让以上做法适应更一般的情况,我们更改 s 的定义为:只考虑 [l,r] 区间的影响时,[mid+1,r] 中的答案。那么 solve 函数中的第一种情况就可以改为 solve(ls,x)+s_{ro},更新答案的操作改为 s_{ro}=solve(rs,mx_{ls}),同时查询操作要改为 solve(rt,0)

例题

四、线段树维护历史值

五、线段树合并

当需要按对应位置合并一些数组,但这些数组并不满时,且合并操作较为简单(线段树能够支持)时可以采用线段树合并;同时也支持线段树所支持的区间修改、查询等操作。

一些问题中,线段树合并可以被长链剖分、dsu on tree 代替

下面介绍两种常见的应用

六、线段树上二分

对于一些需要用二分套线段树上查询的问题,线段树本身就是一个分治的结构,所以可以直接在线段树的结构上进行二分。

例题

七、线段树的结构分析

ZJOI经常有这样一类题目:模拟线段树上的一些操作,查询某种计数信息。这里将给出针对这些问题的几个结论

例题

八、线段树优化建图

常见操作有三种:

对于有 n 个点,m 个连边操作的图,最终连出的总边数为 O(m\log n) 级别。

例题

参考资料

就先总结这些吧,完结撒花!