线段树小记
好像网上部分对于那些历史版本(历史版本和,历史最大值)的操作的讲解都不够直观。
核心思想就是在线段树中维护两个数组 \(A\) 和 \(B\) ,\(A\) 是普通线段树维护的东西,\(B\) 是历史版本的信息,然后有两种操作,一种操作是对于 \(A\) 的修改,另一种就是将 \(A\) 中的一个线段的信息通过一种方式敲到 \(B\) 上,将这一过程记为 \(A\rightarrow B\) 。
首先有两种 tag
,一种是一个对于 \(A\) 的操作,设为 S
,一种是对于 \(A\rightarrow B\) 的 tag
,记为 T
。
然后问题就出来了,因为最后 tag
会堆积成这个样子:
然后就要处理这种东西,其实就是考虑旧的 \(S\) 对于新来的 \(T\) 造成的影响。
这里以区间加,历史版本和为例。
设 \(A_v\) 表示线段树节点所对应区间 \(A\) 数组的和,\(B_v\) 表示所对应 \(B\) 数组的和。
区间加大家都会,对于每个节点维护一个加法 tag
\(S_i\) 记录将要对于所有子节点的 \(A\) 将要加上的值。
考虑对于线段树节点 \(v\) 儿子 \(s\) 的 \(B_s\) 的贡献。
首先单纯没有 \(S\) 的记录非常简单,就是 \(T\) 的次数乘上原来儿子上存的值,这里存一个 tag
\(T_v\) 表示这个系数。
然后就是上方所说旧的 \(S\) 对于每个 \(T\) 的影响,对于每个 \(T\) 最后的贡献就是 \(len_s\times \sum S\) ,其中这个 \(len_v\) 表示区间长度,\(\sum S\) 表示在当前 \(T\) 操作时加法标记的总和,再开一个 tag
\(t_v\) 表示所有 \(\sum S\) 的总和。
最后 pushdown
的操作就成了。
先下放 \(T_v\) 和 \(t_v\) ,再下放 \(S_v\) 就可以了。
然后这个思想的局限性也出来了,首先是线段树对于 \(A\) 操作的局限性,然后就是要求快速计算所谓「旧的 \(S\) 对于新来的 \(T\) 造成的影响」。