前言
CDQ分治和整体二分都是离线算法,并且都是基于分治的思想。大部分非强制在线的树套树题都可以使用整体二分或CDQ分治解决,当然也有一些是不行的,比如动态求区间种类数或者动态求区间 m e x mex mex。
CDQ 分治
分治
首先要了解什么是分治,分治的全称为分而治之,英文名为 d i v i d e a n d c o n q u e r divide\ and\ conquer divide and conquer,和分治相关的算法有很多,譬如线段树,点分治,归并排序等。下面以归并排序为例。
在归并排序中,我们的算法分为以下流程:
- 将 [ l , m i d ] [l,mid] [l,mid] 排序
- 将 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 排序
- 将 [ l , m i d ] [l,mid] [l,mid] 的序列和 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的序列合并,这一步的复杂度是 O ( r − l + 1 ) O(r-l+1) O(r−l+1) 的
这样子的复杂度是 T ( n ) = 2 T ( n 2 ) + O ( n ) = O ( n l o g n ) T(n)=2T(\frac{n}{2})+O(n)=O(nlogn) T(n)=2T(2n)+O(n)=O(nlogn) 的。
而在归并排序的过程中,我们可以顺便把逆序对给求出来,这个求逆序对的思想就是 c d q cdq cdq 分治的核心思想。
具体过程就是,先求出 [ l , m i d ] [l,mid] [l,mid] 的逆序对,再求出 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的逆序对,再求出 x ∈ [ l , m i d ] , y ∈ [ m i d + 1 , r ] x\in[l,mid],y\in[mid+1,r] x∈[l,mid],y∈[mid+1,r] 的逆序对 ( x , y ) (x,y) (x,y) 的数量。由于原序列已经满足了 x < y x<y x<y,我们只需要求 a x > a y a_x>a_y ax>ay 的数量。因此我们可以想到先让 a x , a y a_x,a_y ax,ay 有序,然后根据单调性来求对数,而这个让 x , y x,y x,y 有序,即是归并排序的一个过程。
三维偏序
比如我们要求 a j ≤ a i , b j ≤ b i , c j ≤ c i a_j\le a_i,b_j\le b_i,c_j\le c_i aj≤ai,bj≤bi,cj≤ci 的 ( i , j ) (i,j) (i,j) 对数。
容易想到,我们先按 a a a 排序,然后在这个序列的基础上求解 b , c b,c b,c。这个容易用树套树解决。
那么我们仍然考虑分治,先求 [ l , m i d ] [l,mid] [l,mid] 的,再求 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 的,现在只需要考虑 x ∈ [ l , m i d ] , y ∈ [ m i d + 1 , r ] x\in[l,mid],y\in[mid+1,r] x∈[l,mid],y∈[mid+1,r] 的点对 ( x , y ) (x,y) (x,y) 了。注意到,由于原序列已经按 a a a 排序,我们只需要找 b x ≤ b y , c x ≤ c y b_x\le b_y,c_x\le c_y bx≤by,cx≤cy 的点对 ( x , y ) (x,y) (x,y) 的数量。如果我们可以让 b x , b y b_x,b_y bx,by 是有序的,也就是 [ l , m i d ] [l,mid] [l,mid] 和 [ m i d + 1 , r ] [mid+1,r] [mid+1,r] 中是按 b x , b y b_x,b_y bx,by 升序的。因此我们只需要使用归并排序,在这个过程中用一个树状数组统计答案就好了。
需要注意的是,我们需要先把 a i = a j , b i = b j , c i = c j a_i=a_j,b_i=b_j,c_i=c_j ai=aj,bi=bj,ci=cj 的情况合并为一种。
复杂度是 T ( n ) = 2 T ( n 2 ) + O ( n l o g n ) = O ( n l o g 2 n ) T(n)=2T(\frac{n}{2})+O(nlogn)=O(nlog^2n) T(n)=2T(2