CDQ 分治 学习笔记
CDQ 分治的思想最早由 IOI2008 金牌得主陈丹琦在高中时整理并总结,它也因此得名。
简介
CDQ 分治是一种思想而不是具体的算法,与 动态规划 类似。目前这个思想的拓展十分广泛,依原理与写法的不同,大致分为三类:
- 解决和点对有关的问题。
- 一维动态规划的优化与转移。
- 通过 CDQ 分治,将一些动态问题转化为静态问题。
解决和点对有关的问题
这类问题多数类似于「给定一个长度为 n 的序列,统计有一些特性的点对
CDQ 分治解决这类问题的算法流程如下:
找到这个序列的中点
; 将所有点对
划分为 3 类: 的点对; 的点对; 的点对。
将
这个序列拆成两个序列 和 。此时第一类点对和第三类点对都在这两个序列之中; 递归地处理这两类点对;
设法处理第二类点对。
可以看到 CDQ 分治的思想就是不断地把点对通过递归的方式分给左右两个区间。
在实际应用时,我们通常使用一个函数 solve(l,r)
处理 solve(l,mid)
与 solve(mid,r)
来实现的。剩下的第二类点对则需要额外设计算法解决。
例题:三维偏序
题意:给定一个序列,每个点有
解题思路
三维偏序是 CDQ 分治的经典问题。
题目要求统计序列里点对的个数,那试一下用 CDQ 分治。
- 首先将序列按
排序。 - 假设我们现在写好了
solve(l,r)
,并且通过递归搞定了solve(l,mid)
和solve(mid+1,r)
。现在我们要做的,就是统计满足, 的点对 中,有多个点对还满足 , , 的限制条件。 - 稍微思考一下就会发现,那个
的限制条件没啥用了:已经将序列按 排序,则 可转化为 。既然 比 小, 比 大,那 肯定比 要小。现在还剩下两个限制条件: 与 , 根据这个限制条件我们就可以枚举 , 求出有多少个满足条件的 。 - 为了方便枚举,我们把
和 中的点全部按照 的值从小到大排个序。之后我们依次枚举每一个 , 把所有 的点 全部插入到某种数据结构里(这里我们选择 树状数组 此时只要查询树状数组里有多少个点的) 。 值是小于 的,我们就求出了对于这个点 ,有多少个 可以合法匹配它了。 - 当我们插入一个
值等于 的点时,我们就令树状数组的 这个位置单点 + 1,而查询树状数组里有多少个点小于 的操作实际上就是在求 前缀和,只要我们事先对于所有的 值做了 离散化,我们的复杂度就是对的。 - 对于每一个
,我们都需要将所有 的点 插入树状数组中。由于所有的 和 都已事先按照 值排好序,这样的话只要以双指针的方式在树状数组里插入点,则对树状数组的插入操作就能从 次降到 次。 - 通过这样一个算法流程,我们就用
的时间处理完了关于第二类点对的信息了。此时算法的时间复杂度是 。