分治 2

主要是讲两个东西:
CDQ分治&整体二分

CDQ分治

[模板] 三维偏序

离线——CDQ分治
一维偏序就是归并排序求逆序对?Yes
好,再加一维:
处理这一维我们考虑std::sort水掉这一维,
剩下的一维就直接维护一个树状数组查询即可
好,再加一维:

既然主题是分治的话,就直接用吧
分治流程:
1.划分成更小的子问题
2.解决最小规模的问题
3.处理两个子问题的合并
显然3是最重要的,
因为划分不动脑子递归就行,而最小规模的子问题可能不用解决
分治的核心思想:
考虑一个子问题对于另外子问题的贡献

考虑如何把这个划分成一个更小的问题
既然已经有二维偏序,那就直接用std::sort水掉这一维!
(正确性:对于每个子区间不管再怎么内部排序,右区间显然一定大于左区间)
于是它就是一个二维的问题了
对于这个二维问题,没有办法一开始保证\(a\)std::sort,于是考虑分治:

二分查询区间\([l,r]\),记\(mid=\frac{l+r}{2}\)
对于每一个区间来说,左右区间内部划分成的子问题已经解决了
维护左边\([l,mid]\)对于右边\([mid+1,r]\)的贡献
如果左区间的一个决策点\(j\)对于右区间的\(i\)可能有贡献,
那么显然:\(b_j<b_i\)
先不考虑\(c\)的问题,
因为\(c\)这一维按照二维偏序问题的解法,直接插到树状数组
此时我们已经知道它可能有贡献,应该赶紧加进去,否则就可能会错算
最后对于每个询问,我们只需要扔到树状数组里,查一下前缀和
就知道有贡献的有多少了
注意清空和去重

带修&可离线数据结构

CDQ分治的一个好处就是“降维打击”
就是你甚至可以直接用递归+std::sort
直接把两维变成一维(虽然看起来又加了一维)
具体的方法就是把时间看成一维偏序
对于一个询问,对它有影响的一定是时间偏序靠前的修改
所以就直接当三维偏序就行了
如果是修改就树状数组维护贡献
查询就直接树状数组查询有贡献的
(另外两个维度题里会有限制,转化一下题意即可)

优化DP

就是斜率优化里有一个情形是某个元素不单调的情况
这个时候建议CDQ动态维护凸包
然后还有一个事就是:
有些DP的转移条件可以转换成偏序
然后就可以CDQ做了

posted @ 2022-10-11 21:29  2K22  阅读(30)  评论(0)    收藏  举报