cdq 分治

归并排序

void mergesort(int l, int r) {
	
	if (l >= r) return ;
	int mid = (l + r) >> 1;
	mergesort(l, mid), mergesort(mid + 1, r);
	int i = l, j = mid + 1, k = l;
	for (; i <= mid && j <= r; k++)
		if (a[i] <= a[j]) tmp[k] = a[i++];
		else tmp[k] = a[j++];
	if (i <= mid) for (; k <= r; k++) tmp[k] = a[i++];
	if (j <= r) for (; k <= r; k++) tmp[k] = a[j++];
	for (i = l; i <= r; i++) a[i] = tmp[i];
}

cdq 分治

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

二维偏序

偏序问题都可以用 cdq 分治写。二位偏序的套路为先定第一维,在求第二维。

求逆序对和最长上升序列都是二维偏序。以逆序对为例,两维分别是 i < j ii<j a i > a j a_i >a_j ai>aj。那么以 a i a_i ai 为第一关键字从大到小排序,定了第二维。再查询有多少个 i > j i>j i>j,用树状数组维护即可。这个过程反过来也可以。

三维偏序

n n n 个元素, 第 i i i 个元素有 a i , b i , c i a_{i}, b_{i}, c_{i} ai,bi,ci 三个属性, 设 f ( i ) f(i) f(i) 表示满足 a j ≤ a i a_{j} \leq a_{i} ajai b j ≤ b i b_{j} \leq b_{i} bjbi c j ≤ c i c_{j} \leq c_{i} cjci j ≠ i j \neq i j=i j j j 的数量。
对于 d ∈ [ 0 , n ) , d \in[0, n), d[0,n), f ( i ) = d f(i)=d f(i)=d 的数量。

手画模拟一下过程
cdq 分治_第1张图片
用归并排序的原因是 cdq 分治的递归和归并排序相似,可以降一个 log ⁡ \log log

你可能感兴趣的:(cdq 分治)