【CDQ分治小记】

补充

对于某一维限制如果是min(a,b),或者是max(a,b),可以分两种情况讨论然后用cdq解决这一维限制

概论

在OIwiki上可以看到cdq分治有三种不同的作用:

  1. 解决序列的点对问题
  2. 优化1D1D动态规划
  3. 将动态问题以多一个log代价,转化为静态问题。

但最本质的应该是第三个:以静制动
cdq分治和树套树往往可以互相代替,cdq分治优点是空间和常数,而且相对更容易嵌套,树套树的好处就是可以在线

算法原理

cdq分治的主要过程就是如果有一维,只有前面的对后面的有贡献(为了保证这个条件,通常要按多关键字排序),我们可以分治这一维
考虑一个既有修改C也有查询Q的动态问题,把操作序列记下来,如果C可以向Q进行分批次的贡献,那么这个问题就可以以一个log的代价转化为静态问题(也就是所有查询都在修改后)
一般来说,贡献可以相加的形式是比较容易做的

例子:在一个平面内,矩形加,矩形求和

我们发现直接维护比较困难,考虑离线做法:
一个查询Q是由之前所有的C累加而来,那么设cdq(l,r)表示在区间[l,r]中,Q累加的贡献,
那么递归调用cdq(l,mid),cdq(mid+1,r),然后考虑[l,mid]中所有的C对[mid+1,r]中所有Q的贡献,这就变成了一个静态问题,可以用扫描线+历史和线段树解决

经典例题:多维偏序
在一个k维空间中有n个点,第i个点的坐标为\((a_{i,1},a_{i,2},\cdots ,a_{i,k})\),对每个点求出其前缀超立方体所包含的点数

cdq处理的是动态问题,所以我们先把这个静态问题转化为动态问题,这里有一个经典套路:选一个维度进行排序,把这个维度当成时间维,那么k维的静态问题就转化为了k-1维的动态问题,一般来说选取的时间维通常是比较简单的维度,只有一个限制
然后套用cdq分治,这个k-1维的动态问题就转化为了k-1维的静态问题,如果维度依然较高,可以持续这个过程,最后一般用一个数据结构维护最后一个维度。

优化1D1D动态规划

实际上可以用cdq分治优化的模型就是多维偏序的模型,只是这里必须要先cdq(l,mid)再从[l,mid]转移到[mid+1,r],最后再cdq(mid+1,r),这是要保证dp值算出后才能进行转移。

细节

  1. 对于各个维度相同的点一般来说要在最初先合并,一块算贡献,当然,如果有一个维度没有要求小于等于而是小于,就无所谓了
  2. cdq分治的排序,除了用数据结构维护的那一维,一定要注意按照这种排序规则是否,只会从前往后贡献(极易出错)
  3. cdq嵌套时,通常在结构体中多记录一些信息,用1,2表示在上一层cdq中,其处于左区间还是右区间。
  4. 一般来说,在结构体中存一个变量id,表示对应的点的编号,这样就不用在结构体中保存答案了,只需再开一个ans数组,存下每个点的值,这样在多个cdq嵌套时,可以减少sort的次数,一定程度上减小常数,对于可以后序遍历的cdq分治,也可以用归并排序减小常数。

总结

“cdq分治”就是指在一维上只有前面对后面有贡献,比如数据结构只有时间前面的修改对时间后面的询问有贡献,也可以使用这个算法,然后分治这一维,分治的每层需要维护分治中线左边对右边的贡献。
复杂度\(O(n\log n)\)

posted @ 2022-08-20 08:31  glq_C  阅读(77)  评论(0)    收藏  举报