CDQ 分治多维偏序问题小结

独自空忆成欢 提交于 2020-08-16 19:10:17

一、分治基础

1. 归并排序

题目大意:给定一个长度为 n 的数组,你需要对它进行排序。1≤n≤105

Solution:

考虑把整个数组分成两个部分,等两部分都排完序后再把这两个有序的数组进行合并。

动图演示

合并的过程可以用双指针,时间复杂度是 O(n) 的。

这样总时间复杂度 T(n)=2T(n/2)+O(n),得出 T(n)=O(n log n)。

void solve(int l,int r){
    if(l==r) return ;
    int mid=(l+r)>>1;
    solve(l,mid),solve(mid+1,r);
    int x=l,y=mid+1,cnt=l;
    while(x<=mid&&y<=r){
        if(a[x]<a[y]) t[cnt++]=a[x++];
        else t[cnt++]=a[y++];
    }
    while(x<=mid) t[cnt++]=a[x++];
    while(y<=r) t[cnt++]=a[y++];
    for(int i=l;i<=r;i++) a[i]=t[i];
}

所谓分治,就是把一个规模为 n 的问题分解为两个规模减半的子问题,解决完子问题后再通过子问题的结果得到原问题的答案。

2. 棋盘覆盖问题

 题目大意:有一个大小为 2n×2n 的棋盘,其中抠掉了一个方格。你需要用这种 L 形的骨牌去覆盖这张棋盘上其它剩余的部分。求一组解。1≤n≤10。

 Solution:

我们把整个棋盘沿着中心线分成四个部分,这样被抠掉的那个格子一定位于其中一个部分里。

在中心放一个 L,使得其刚好覆盖了其余三个部分各一个格子:

然后就可以递归。由于不需要合并,时间复杂度和输出同阶。

二、关于 cdq 分治

有的时候,后面的值会依赖前面的值。比如 DP 的过程中,要求出后面的 DP 值,我们就需要先求出前面的 DP 值。

这时候就需要用到 cdq 分治。这个分治的思路如下:

  1. 递归处理左边
  2. 计算左边对右边带来的贡献
  3. 递归处理右边

三、多维偏序问题

1. 最长上升子序列(二维偏序)

题目大意:有 n 个数 a 1,...,a n,求最长上升子序列的长度。1≤n≤10 5

Solution:

设 f[i] 表示以 i 结尾的最长上升子序列的长度。

然后可以用 DP 来求解:f[i]=minj<i&aj<ai f[j]+1

直接做时间复杂度是 O(n2) 的。

考虑优化这个算法。

设当前分治区间是 [l,r],我们递归求完了 [l,m] 的答案,接下来要处理这一段对 [m+1,r] 的贡献。

把位于 [l,m] 的点看做插入,[m+1,r] 的点看做查询, 然后把整个区间按照 ai 排序。问题转化为支持插入 f[i] 和查询当前所有 f 的最大值。

只需要记录一个前缀最大值就可以了。

时间复杂度:O(n log n)。

可以不用 cdq 分治。我们先把 ai 离散化,然后开一个树状数组。只需要实现单点修改和前缀查询最大值。时间复杂度还是 O(n log n)。

2. 三维偏序

题目大意:有 n 个元素,每一个元素有一个 ai 和 bi,求两个值都单调的最长上升子序列。1≤n≤105

Solution:

还是先考虑 n2 算法:f[i]=minj<i&aj<ai&bj<bi f[j]+1

然后 cdq 分治。

我们把 [l,r] 内的元素按照 ai 排序。接下来问题转化为支持插入一个 bi 以及询问所有满足 bj<bi 的 f[j] 的最大值。

用树状数组解决。总时间复杂度 O(n log2 n)。

3. 四维偏序

题目大意:现在每一个值有三个属性 ai,bi,ci,还是求最长上升子序列。1≤n≤50000。

先按照 ai 排序,cdq 分治后分治区间内转化为三维偏序问题。

然后再 cdq 一次,内层用树状数组实现。

时间复杂度:O(n log3 n)

四、总结

如果我们有 k 个限制,那么 cdq 一次之后就可以去掉其中的一个限制,其中时间复杂度多一个 log。

不过 log4 及以上的复杂度就已经不如 O(n2) 算法快了,所以在实际应用中最多就是 cdq 套 cdq。

绝大多数 cdq 分治的题目都可以转化为 k 维偏序(或者 k 维数点)。

 

注:这道题(三维偏序) 给的是一个 n 个元素的集合,每个元素有三个属性,是无序的。而上面所写的三维偏序,这 n 个元素是有序的,所以下标也算一个属性。其他的同理。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!