CDQ 分治学习笔记

引入

  • 给定一个长度为 \(n\) 的序列,每一个元素都有一个键值 \(a\),记 \(f(i)\)\(a_i \le a_j\)\(i \ne j\)\(j\) 的个数(一位偏序)。
  • \(d \in \left [ 0, n \right )\)\(f(i) = d\)\(i\) 的数量。
  • 这很简单,我们不做讨论。
  • 那如果加一维 \(b\) 呢?(二维偏序)
  • 只需要先按照 \(a\) 排序,这样就可以去掉 \(a\) 这一维的限制。
  • 然后用你喜欢的方式维护逆序对即可。
  • 再加一维呢?(三位偏序)
  • 好像就没那么简单了……

正题

概念

cdq 分治主要用来解决二元组问题。

传入 \((l, r)\),则所求二元组(有序) \((i, j)\) 满足 \(l \le i, j \le r\)

取该区间中点 \(m\)

  • \(l \le i, j \le m\),分治 \((l, m)\)
  • \(m + 1 \le i, j \le r\),分治 \((m + 1, r)\)
  • 解决 \(l \le i \le m \lt j \le r\) 的情况。

模板

void cdq(int l, int r) {
    int mid = (l + r) / 2;
    cdq(l, mid), cdq(mid + 1, r);
    // solve
}

例题

三维偏序

回到刚刚的问题,我们试着用 cdq 分治解决刚刚的问题。

考虑先按照 \(a\) 排序,就可以省下一维的复杂度。

此时就有 \(l \le i \le mid\)\(mid + 1 \le j \le r\) 的情况。

先将 \(l \sim mid\)\(mid + 1 \sim r\) 分别按照 \(b\) 排序。

虽然分别排序会打乱 \(a\) 的顺序,但是 \(\forall i \in \left [ l, mid \right ], j \in \left [ mid + 1, r \right ]\) 均有 \(a_i \lt a_j\)

所以只需要分别双指针一下即可统计。

struct fenwick {
#define lowbit(x) (x & -x)
    int c[N];
    void change(int x, int v) {
        for (; x <= k; x += lowbit(x)) {
            c[x] += v;
        }
    }
    int ask(int x) {
        int ans = 0;
        for (; x >= 1; x -= lowbit(x)) {
            ans += c[x];
        }
        return ans;
    }
} bit;

void cdq(int l, int r) {
    if (l >= r)
        return;
    int mid = (l + r) / 2;
    cdq(l, mid), cdq(mid + 1, r);
    sort(a + l, a + mid + 1, [&](node x, node y) {
        return (x.b != y.b) ? (x.b < y.b) : (x.c < y.c);
    });
    sort(a + mid + 1, a + r + 1, [&](node x, node y) {
        return (x.b != y.b) ? (x.b < y.b) : (x.c < y.c);
    });
    int i = l, j = mid + 1;
    for (; j <= r; j++) {
        while (i <= mid && a[i].b <= a[j].b) {
            bit.change(a[i].c, a[i].num);
            i++;
        }
        a[j].ans += bit.ask(a[j].c);
    }
    for (int k = l; k < i; k++) {
        bit.change(a[k].c, -a[k].num);
    }
}

不过这也不一定只能用一个 cdq 分治,我们其实可以再在里面嵌套一个 cdq 分治,此时也可以维护三维偏序。

这种方法更加普遍,如四维偏序、五维偏序等也可以用这种方法。

代码我就不写了。

posted @ 2024-11-07 21:18  Reveriean  阅读(15)  评论(0)    收藏  举报