线段树用法技巧总结

常见信息维护

区间和,区间乘积,区间 \(\max ,\min\)

最大子段和:考虑维护最大前后缀,根据最大前后缀能维护最大子段和。
具体的,
\(suml(l,r) = \max(suml(l,mid),sum(l,mid) + suml(mid + 1,r))\)
\(sumr(l,r) = \max(sumr(mid + 1,r),sum(mid + 1,r) + sumr(l,mid))\)
\(ans(l,r) = \max(ans(l,mid),ans(mid + 1,r),sumr(l,mid) + suml(mid + 1,r))\)

最大上升子串:类似于最大子段和。
具体的,考虑维护前后缀最大上升子串,然后区间合并判断 \(a_{mid}\)\(a_{mid + 1}\) 能否满足合并条件即可。

最大不相邻子集和:考虑维护四个信息 \(f_{0/1,0/1}\),其中第一个 \(0/1\) 表示选出的不相邻子集是否可含有左端点 \(l\)\(0\) 表示不能,\(1\) 表示能);第二个同理,表示是否可含有 \(r\)
具体的,
\(f(l,r)_ {0,0} = \max(f(l,mid)_ {0,1} + f(mid + 1,r)_ {0,0},f(l,mid)_ {0,0} + f(mid + 1,r)_ {1,0})\)
\(f(l,r)_ {0,1} = \max(f(l,mid)_ {0,1} + f(mid + 1,r)_ {0,1},f(l,mid)_ {0,0} + f(mid + 1,r)_ {1,1})\)
\(f(l,r)_ {1,0} = \max(f(l,mid)_ {1,0} + f(mid + 1,r)_ {1,0},f(l,mid)_ {1,1} + f(mid + 1,r)_ {0,0})\)
\(f(l,r)_ {1,1} = \max(f(l,mid)_ {1,0} + f(mid + 1,r)_ {1,1},f(l,mid)_ {1,1} + f(mid + 1,r)_ {0,1})\)

区间平方和:叶子节点设为 \(w^2\) 即可加和维护。
对于区间加,展开即可:
\(sqsum(l,r) = sqsum(l,r) + 2 \times tag \times sum(l,r) + (r - l + 1) \times tag^2\)

区间方差:展开原式,容易得到方差即为区间平方和除以 \(n\) 减去区间平均数。

待记录。。

势能分析

对于一些线段树操作,当 \([ql,qr] \in [l,r]\) 的时候就不能直接打标记,而是需要继续递归下去才能完成这些操作,那么就需要对线段树势能的分析来保证时间复杂度,使 \([l,r]\) 递归到满足某种条件的时候能够直接操作并停止递归。此类线段树称作势能线段树。

常见势能分析

区间开方:定义线段树一个区间的势能为 \(\max\) 需要开方多少次才会变为 \(1\)

当对于 \([l,r]\) 势能为 \(0\),那么就不管这个区间。(实际上就是 \([l,r]\) 全为 \(1\)

区间取模:定义势能为 \(\max\) 还需要取模多少次才会小于 \(mod\)

\([l,r]\)\(\max\) 小于 \(mod\) 的时候就不用递归下去了,因为每次取模值至少减少一半,所以是 \(\log\) 的。

区间赋值为 \(\tau(x)\):对于一个数 \(x\)\(\tau(x)\) 最大为 \(\frac{x}{2}\),故也是 \(\log\) 的。

区间除法下取整:维护 \([l,r]\)\(\max,\min\),如果这个区间 \(\max - \lfloor \frac{\max}{x} \rfloor = \min - \lfloor \frac{\min}{x} \rfloor\),那么这个除法操作对于这个区间的修改等价于区间加法。

区间按位与 + 或:维护区间与/或,当这次操作对区间与和区间或造成的变化量相同,则可以直接打区间加法的 \(tag\)

待记录。。

posted @ 2024-10-14 13:47  songszh  阅读(5)  评论(0编辑  收藏  举报