线段树

  • 基本知识

    定义上线段树就是一种可以维护区间信息的数据结构,在原数列的基础上多加了一些点,一层一层往上合并的过程。

    特殊的就是打 lazy tag 方式和其他的一些线段树处理方式。

    多种标记的时候需要分析优先级,比如加法和乘法的优先级。

  • 典型线段树

  1. 区间加法乘法:考虑分配律,乘法的时候应该先下传乘法标记,加法标记需要乘上本来的乘法标记。
  2. 区间最大子段和:每个区间维护区间和 \(sum\),以左端点开始的最大子段和 \(lsum\),以右端点开始的最大子段和 \(rsum\),整个区间的最大子段和 \(msum\),合并时有:

    \[\large sum_{rt}=sum_{lson}+sum_{rson} \]

    \[\large lsum_{rt}=\max\{lsum_{lson},sum_{lson}+lsum_{rson}\} \]

    \[\large rsum_{rt}=\max\{rsum_{rson},sum_{rson}+rsum_{lson}\} \]

    \[\large msum_{rt}=\max\{msum_{lson},msum_{rson},rsum_{lson}+lsum_{rson}\} \]

  3. 按位线段树:有些题需要处理二进制的问题,就可以把数字拆位,建若干个线段树进行处理。(这个还不会,咕咕咕)
  • 线段树拓展

  1. 主席树

    就是把每次更改的版本存下来,但是如果每一次都存肯定不行,所以只将修改的点插入到原本的线段树上,如图:

    经典的例题就是静态区间第 \(k\) 小。需要建一棵值域主席树。对于寻找当前区间 \([l,r]\) 中值域里的第 \(k\) 大,我就正常线段树二分,但是同时二分两棵线段树,对于一个 \(mid\),前一半的值域在 \([l,r]\) 中数的个数等价于 \([1,r]\) 中数的个数减去 \([1,l-1]\) 中数的个数

    拓展一下就是动态区间第 \(k\) 小,需要树套树我们可以给主席树套一棵树状数组,每次暴力修改完在树状数组上维护,注意树状数组记录的其实只是每一棵主席树的树根,所以跑树状数组每一个点时要在对应的主席树上进行修改。查询可类比上文,上文中我们记录了两个树根,现在我们可以把树状数组上的一些相关的树根开两个数组记一下,每次二分就把所有树的答案累加起来。

  2. 线段树合并

    注意合并要用动态开点线段树,不然复杂度会变成 \(O(n\log^2n)\) 的,因为线段树有 \(O(n\log n)\) 个节点,合并又是 \(O(\log n)\) 的。

    我们还是在树上走,如果走到一点地方时存在节点(可能是一个或两个)为空,就可以直接返回另一个节点,否则就往下递归,到叶子时合并回来即可。

    分析一下复杂度。

    容易发现:在合并两棵树的过程中走到有空节点的时候就返回了,相当于走一个点就会删掉一些点,所以总复杂度不会超过总点数也就是 \(O(n\log n)\)

    为什么需要合并线段树,因为对于一些问题我们需要合并的信息是 \(O(n)\) 级别的,对于这类式子我们肯定需要一种 \(O(\log)\) 的方式去优化。

    如何去理解合并的过程,如果真的每一个点都开一个线段树那肯定爆炸。其实我们是把每个点对应在一段区间上,或是下标或是值域,然后对于每一个点的线段树动态开点,最后是合并过程中并不是单纯的加加减减,而是要根据你的式子去还原。

  3. 李超线段树

    用于处理线段(直线)最大值的问题,通常用于 DP 优化等,它可以快速查询位置上纵坐标最大/小的线段编号以及数值。考虑这种东西就很适合去解决一些需要从区间中找最值转移状态的题。

    板子的话其实没什么用,一般都不会这么考。

  4. 扫描线

    侠义上指的是矩形面积并,广义上是处理二维数点或者统计答案的数据结构。

    咕咕咕

  5. 树套树

    字面意思,就是树的每个节点又代表一棵树。这个考的很多,真的很烦。

  6. 线段树优化建图

    例题就是 Legacy,不过太久远了,大致意思就是将建出来的线段树的节点进行连边,这样跑最短路(忘了是不是了)。

    题型较少,咕咕咕

posted @ 2024-11-26 19:49  God_Max_Me  阅读(269)  评论(0)    收藏  举报