1.分块(在线)
把要维护的序列分成
⌈n√⌉
块, 每块长度
⌊n√⌋
(
最后一块的长度为
n−⌊n√⌋2
)
对于单次区间操作:
被该区间包含的整块打上标记, 左端和右端剩余部分(小于
2n√
个)直接暴力操作, 复杂度为
O(n√)
代码:分块
2.莫队(离线)
对于一系列区间操作:
假设我们在已知区间
[l,r]
的答案, 在
O(f(n))
的时间复杂度内能够得到
[l−1,r],[l+1,r],[l,r−1],[l,r+1]
的答案, 按照一定的顺序将操作排序, 使得在相邻的两次操作区间进行上述转移的复杂度为
g(n)
, 通过暴力转移来进行操作, 时间复杂度为
O(f(n)⋅g(n))
经典排序方法
我们利用上面的分块算法将序列分为 ⌈n√⌉ 块, 当2个询问区间的左端点在同一块时, 按照右端点来排序, 否则按照左端点来排序, 不难证明完成全部转移的复杂度为 O(nn√)
代码:莫队
3.cdq分治(离线)
对于多维偏序问题:
这里讨论最简单的3维偏序问题: 在三维坐标中一个点有3个属性
x,y,z
, 定义点
(xi,yi,zi)
小于另外一个点
(xj,yj,zj)
当且仅当
xi≤xj
且
yi≤yj
且
zi≤zj
, 对于每一个点回答比该点小的点的个数
先对第一维
x
进行升序排序, 并对点编号, 对于编号在
代码:cdq分治
4.整体二分(离线)
对于一些列区间询问:
考虑单个询问区间为
[l,r]
的询问: 如果该询问能够在不改变原序列且复杂度只和该区间的长度线性相关, 那么就可以使用整体二分来解决所有的询问
对于答案区间
[l,r]
, 我们取中点
mid=l+r2
, 如果该询问的答案小于或等于
mid
那么将该询问划分到左区间, 否则划分到右区间, 递归处理左区间和右区间, 复杂度
O(nlogn)