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 分治
cdq 分治是对时间分治,适用于影响独立的情况。
- 递归处理左边。
- 计算左边对右边带来的贡献。
- 递归处理右边。
二维偏序
偏序问题都可以用 cdq 分治写。二位偏序的套路为先定第一维,在求第二维。
求逆序对和最长上升序列都是二维偏序。以逆序对为例,两维分别是 i < j i<j i<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}
aj≤ai 且
b
j
≤
b
i
b_{j} \leq b_{i}
bj≤bi 且
c
j
≤
c
i
c_{j} \leq c_{i}
cj≤ci 且
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 分治的递归和归并排序相似,可以降一个
log
\log
log。

浙公网安备 33010602011771号