感谢 mlystdcall 的透彻讲解
本文里没有的代码可以去这里查看
cdq分治可以用来解决多维偏序问题
优点:代替复杂数据结构,代码好写(类似归并排序),常数小
缺点:必须离线
重要原则:cdq分治归根到底是分治,只用考虑分治后左边对右边的影响,其他的都是递归下去的子问题
原则不懂可以先记住,边看边理解
二维偏序
例:给定N个有序对(a,b),求对于其中的每个的(A,B),满足a<A且b<B的有序对(a,b)有多少个?
逆序对问题,换了个马甲而已。
各种数据结构都能水过去
这里的二维很显然,就是一个a,一个b
建议用归并排序练习一下
排序前位置递增,排序后大小递增,在排序的时候统计逆序对。
归并是cdq的雏形,不能说毫不相干,只能说一模一样
带修改的类二维偏序
例:
有一个n个元素的序列,初始值全部为0,有两种操作:
操作1:格式为1 x k,把位置x的元素加上k。
操作2:格式为2 x y,求出区间[x,y]内所有元素的和。
P3374 【模板】树状数组 1好家伙,马甲都没换
各种数据结构都能水过去
用cdq怎么做?
先找二维分别是啥
第一维是时间顺序(操作顺序),很容易被忽略
第二维是操作(询问可以用前缀和的思想拆分为两个位置)的位置
归并排序前时间递增,排序后位置递增,排序中统计。
这里详细讲一下。
归并的时候将lr分为了lmid(简称L)和mid+1~r(简称R)两块。
一个修改(设为X)怎么才能对一个询问(设为Y)产生影响?X的时间和位置都比Y靠前
L里的时间都比R早,L里边已经按照位置排好序了(但时间是乱的),R也一样。
双指针对L和R的位置处理一下就行了,顺便统计。
三维偏序
P3810 【模板】三维偏序(陌上花开) 好家伙,马甲都没了
模板题而已
一维排序,二维cdq,三维树状数组
你也可以试试套一下别的
建议看着代码理解
代码看这里
四维偏序/cdq套cdq
例:给定n个有序四元组(a,b,c,d),求对于每一个四元组(A,B,C,D),有多少个四元组(a,b,c,d)满足a<A && b<B && c<C && d<D。
其实就是三维偏序加了一维
套娃开始了
其实我们可以把这里的(c,d)看做三维偏序里的(c),那么刚才的树状数组就要换成能维护二维信息的数据结构,空间&时间复杂度爆炸
我们思考一下,cdq优点有哪些?它能把具体的数值变成L和R的区分,省去了比较的过程。我们以L和R区分为基础(此时就省去了一维),再处理剩下的几维。
按照这个思路,我们cdq的时候其实就是分为了(aL,b,c,d)和(aR,b,c,d),我们顺便记录一下每个元素按照a是属于aL还是属于aR
我们把这个复制一遍,按照b排序(此时a的乱的,但是根据a带有L或R的标记),我们顺便记录一下每个元素按照b是属于bL还是属于bR
此时每个元素就是分为了(aL/aR,bL/bR,c,d)
要是想造成贡献,只能是(aL,bL,c,d)对(aR,bR,c,d)造成的
然后c这一维双指针,d这一维树状数组
练习题:
P3810 【模板】三维偏序(陌上花开)三维偏序
P5459 [BJOI2016]回转寿司 题解
P4093 [HEOI2016/TJOI2016]序列
P4169 [Violet]天使玩偶/SJY摆棋子
[HZOI 2016]偏序 COGS 2479 四维偏序
[bzoj2989&4170: 数列]