cdq分治的思想非常简单, 就是每次分别递归处理在左半边区间内和右半边区间内答案的贡献, 然后像归并排序一样把左半边和有半边合起来, 顺带统计一下左半边区间中的修改对右半边区间中的询问做出的贡献。 归并排序求逆序对就是cdq分治最简单的应用了。
容易分析得出应用到cdq分治时需要满足这些条件:每个修改对于每个询问的影响都是独立的; 我们可以快速地统计出来一堆指定修改操作对一个询问总共的贡献。
经典的应用比如说数点问题。
bzoj 3262: 陌上花开
是最简单的三维数点, 这时候直接把第一维排一个序, 然后第二维上cdq分治, 合并的时候如果一个询问点原属于右半边区间, 那么所有原属于左半边区间(即第一维比询问点大)且合并后在它前面(即第二维比询问点大)且第三维比询问点大的点都会对询问点有着1的贡献。 所以只需要把合并后的序列从小往大扫一遍, 然后用一个树状数组存一下当前原属于左半边区间且第三维大于x的数有多少个, 那么每一个询问点在这次合并中就都可以做到O(logn)的查询了。
Tsinsen A1485. Catch The Penguins 抓企鹅(张闻涛)
四维数点
有很多种办法都可以搞, 比较简单的比如说上一个三维数点然后开一个树状数组套平衡树就行了。
yy了cdq分治套cdq分治的做法, 也非常简单。 接着上面三维的那个说,我们合并完左右区间后想要加入在pos处的询问的答案是所有当前位置小于pos且原来在左半边区间的点, 而这个就又转化为了一个三维数点问题了! 原来在左半边的所有询问和原来在右半边的所有修改在当前都是没有意义的了删掉就好了。
这种做法的一个非常好的地方就是可以一直加维数加下去, 每加一维就套上一层cdq分治, 时间复杂度套一个log, 但是它的优点在于空间复杂度始终是O(n)的啊O(n)的啊, 当套到更多维的时候树套树会越发地不好写但是这样做始终非常好些哒。