[学习笔记]线段树骚操作选讲
其他
2018-12-08 20:49:47
阅读次数: 0
引入
- 众所周知,线段树可以维护序列,进行区间操作
- 单点加 + 区间求和
- 区间加 + 区间求和
- 区间加 + 区间乘 + 区间求和
- (省略
+∞ 行)
- 但有些操作不能像上面三个问题一样通过简单的打标记 + 提取区间解决
- 而需要用到一些 trick
一、势能线段树
- 我们知道,线段树能够通过打标记实现区间修改的条件有两个:
- (1)能够快速处理标记对区间询问结果的影响
- (2)能够快速实现标记的合并
- 但有的区间修改不满足上面两个条件
- 但某些修改存在一些奇妙的性质,使得序列每个元素被修改的次数有一个上限
- 可以在线段树每个节点上记录一个值,表示对应区间内是否每个元素都达到修改次数上限
- 区间修改时暴力递归到叶子节点,如果途中遇到一个节点,这个节点的对应区间内每个元素都达到修改次数上限则在这个节点 return 掉
- 可以证明复杂度为
O(nlogn×修改次数上限)
- 用几个简单的栗子说明一下
一、区间开平方,区间求和
- 一个数
x 被开平方
O(loglogx) 后会变成
1 或
0 ,继续开根后不变
- 所以线段树节点上用一个变量记录是否区间内全为
1 或
0
- 修改时递归到叶子,如果到达了区间内全为
1 或
0 的节点则 return 掉
- 复杂度
O(nlognloglogx)
二、区间取模,区间求和
- 一个数
x 对
p 取模,如果
x≥p 则
x 至少变小一半
- 每个节点维护区间和以及区间最小值
- 区间对
p 取模时仍然递归到叶子
- 如果某节点的区间最小值小于
p 则 return 掉
- 复杂度
O(nlognlogx)
三、区间除(下取整),区间加,区间求和
- 区间整除
1 是无效的,直接跳过
- 否则整除一个数会使区间内最大值与最小值的差至少减小一半
- 维护区间最小值和最大值以及区间和,区间加标记
- 整除时递归到叶子
- 如果最小值和最大值的差为
0 ,则该区间内所有数都相等
- 直接打上标记,注意这时候标记可以处理对区间和的影响
- 复杂度
O(nlognlogx)
二、李超树 / 李超线段树 / 超哥线段树
- 考虑经典问题
- 维护一个二维平面
- 支持横坐标
[l,r] 范围内插入一条线段,查询某个横坐标上的最高点
- 换成人话,区间对一个等差数列取
max ,单点查值
- 线段树每个节点维护一个标记(一条线段)
- 仍然把
[l,r] 拆成线段树上不超过
O(logn) 个区间
- 我们要处理的关键问题是标记的合并,也就是两条线段
l1 ,
l2 放在一起的情况
- 如果在当前节点对应区间
[l,r] 内
l1 完全在
l2 之上,则该区间打上标记线段
l1
- 如果
l2 完全在
l1 之上同理
- 最重要的情况:
l1 和
l2 在横坐标
mid=⌊2l+r⌋ 的左边,
l 的右边位置相交,在
[l,r] 的右半段
l2 在
l1 之上
- 这时候将
l2 保留在当前节点上,
l1 的前半段下传到左子节点
- 注意这时候
l1 的前半段可能会和左子节点缓存的线段相交
- 所以这时候需要往左子节点递归
- 还有
3 种情况和上面差不多
- 往交点所在的子节点递归,另一半区间内在上方的线段保留,在下方的线段下传
- 复杂度
O(nlog2n)
三、线段树维护单调子序列
- 考虑经典问题
- 给定一个序列,支持单点修改
- 询问给出
[l,r]
- 求有多少个
i∈[l,r] 满足
i=l 或者
[l,i−1] 内任何一个数都不大于第
i 个数
- 换句话说,求
[l,r] 内有多少个位置
i 是
[l,r] 内对应的以
i 为结尾的前缀最大值
- 定义函数
query(u,x)
- 表示线段树
u 节点对应区间内,有多少个数不小于
x 且是对应区间的前缀最大值
- 线段树上维护区间最大值
- 如果
u 对应的区间最大值小于
x 则
query(u,x)=0
- 设
u 的左右子树分别为
lc 和
rc
- 如果
lc 的最大值小于
x 则
query(u,x)=query(rc,x)
- 否则
query(u,x)=query(lc,x)+query(rc,maxlc)
- 其中
maxlc 为节点
lc 对应区间最大值
- 注意到
query(rc,maxlc) 仅和
u 有关
- 所以在节点
u 上存储一个变量
riu=query(rc,maxlc)
- 这样就能通过
O(nlogn) 的建树之后
O(logn) 查询了
- 修改直接重新计算
max 和
ri ,
O(log2n)
- 询问时把
[l,r] 拆成线段树上的
m (不超过
O(logn) )个区间
[l1,r1] ,
[l2,r2] ,…,
[lm,rm]
- 设对应的节点分别为
u1,u2,…,um
- 并另设
pre ,初始为
−∞
-
i 从
1 到
m ,重复
m 次下面的操作
- (1)将
query(ui,pre) 加进询问结果
- (2)如果
query(ui,pre)̸=0 则
pre←maxui
- 复杂度
O(log2n)
- 总复杂度
O(nlog2n)
四、题目
转载自blog.csdn.net/xyz32768/article/details/84398038