00:00:00
CDQ 分治 笔记
一、二维偏序
给定一个序列,求每个
满足 的个数。

先将序列按

然后分成
先计算小区间的答案再计算大区间的答案,计算答案以
将两个分别按
如图,

因为
cpp
void cdq(int ls, int rs) {
if (ls >= rs)
return;
int mid = (ls + rs) >> 1;
cdq(ls, mid);
cdq(mid + 1, rs);
sort(a + ls, a + mid + 1, cmp2);
sort(a + mid + 1, a + rs + 1, cmp2);
for (int i = ls, j = mid + 1; j <= rs; j++) {
while (i <= mid and a[i].b <= a[j].b) i++;
a[j].cnt += i - ls;
}
}为什么不会算重?如下图,

为什么不会算漏?观察下图我们可以发现

二、三维偏序
最后记得将树状数组还原。
cpp
void cdq(int ls, int rs) {
if (ls >= rs)
return;
int mid = (ls + rs) >> 1;
cdq(ls, mid);
cdq(mid + 1, rs);
sort(a + ls, a + mid + 1, cmp2);
sort(a + mid + 1, a + rs + 1, cmp2);
int i = ls, j = mid + 1;
for (; j <= rs; j++) {
while (i <= mid and a[i].b <= a[j].b) {
update(a[i].c, a[i].cnt);
i++;
}
a[j].ans += query(a[j].c);
}
i--;
for (; i >= ls; i--)
update(a[i].c, -a[i].cnt);
}