CDQ分治可以代替一些高维的数据结构
例行 srO 陈丹琦
诶 今天是\(\pi\)日诶! QwQ
沙茶的 CDQ分治不详解
CDQ分治可以用来解决一些高维的偏序问题, 并可以适当的代替高维的数据结构
我认为 CDQ分治基本与普通的分治的最大区别就在于用左子区间的信息去修改维护右子区间的答案(就和归并排序一样, 或者说归并也是一种CDQ分治))
三维偏序
大体过程:
- 预处理, 将整个序列按照偏序的第一关键字排序
- 分,
将要处理的区间(询问和修改都有)
[le, ri]
分成[le, mi] + [mi + 1, ri]
, 然后递归, 直到le == ri
, 返回 - 治, 将左右区间分别按照偏序的第二关键字排序, 就像归并排序一样,
一个指针
dql
扫描[le, mi]
, 一个指针i
扫描[mi + 1, ri]
, 并时刻保证dql
的第二关键字比i
的第二关键字要小, 然后用数据结构(通常树状数组)维护第三关键字, 用左子区间的扫描更新右子区间的答案
复杂度\(n \lg^2 n\)
没了? 没了
非常优雅 非常好写
代码比口胡容易系列, 什么不懂的一看代码就懂...
四维偏序
没写过...坑...待填...
沙茶写过的 一些水题
保证难度递增
3262: 陌上花开
非常裸的三维偏序, 主要处理花相等的情况: 每次修改树状数组的时候不是加一而是加这个数出现的次数
1 | /************************************************************** |
1176: [Balkan2007]Mokia
依旧是个裸题, 把询问差分成四个前缀矩形即可
注意排序的时候还要按照其他关键字来排序_(:з」∠)_还要别把询问给当成修改给维护了...然后差分加一减一怎么现在还错啊QAQ还有别忘了cdq之前还要排一次序
1 | /************************************************************** |
2716: [Violet 3]天使玩偶
这题好神啊...参考了课件和CA爷爷的代码
只考虑左下角的加点对答案的影响, 如果在左下角加入一个点\((X, Y)\), 那么他对询问\((X_0, Y_0)\)的影响就是\(ans = min(ans, (X_0 - X) + (Y_0 - Y) = X_0 + Y_0 - (X + Y))\), 而 \(X_0 + Y_0\)已知, 那么问题就转化成找一个最大的\((X + Y) 满足 X < X_0, Y < Y_0\)看到这个...又是偏序, 又可以CDQ辣...
在找每一个修改的时候, 我们把它横坐标的位置\(B_i\)修改为\(max(B_i, X + Y)\), 然后查询的时候查询区间\((1, Y_0)\)的最大值即可(其他约束条件已经由分治去掉), 用树状数组维护一个最大值即可
然后考虑其他方向, 你可以用一个最大的坐标减去坐标来做, 具体看注释和代码
然后...你就可以卡常辣!
- 树状数组的清空不用
memset
而是遍历区间内包含的修改然后一个个置为0(好像全网就我一个傻不拉几的写的memset
?) - 每次返回上一层的时候用归并而非每一次都
sort
一遍, 实测快了3倍左右 - 读入优化 + inline + register + const + 手写带const的 max / min 而非define 大概快了100 ms+-
- 开小数组, 但注意bzoj的数据范围有问题, \(n, m\)的范围并非保证的 \(3 \times 10^5\) 而是 \(5\times10^5\) ...
还有一个小细节...坐标可以为0,
而树状数组下标不能为0...所以坐标在读入之前都应该加一,
maxz
也应该在最后加一防止计算新坐标的时候出现0坐标
1 | /************************************************************** |
By 四处蹭脸熟的 Cansult