「LOJ 112」三维偏序

题目链接:LOJ 112

有 $n$ 个元素,第 $i$ 个元素有 $a_i$、$b_i$、$c_i$ 三个属性,设 $f(i)$ 表示满足 $a_j \le a_i$ 且 $b_j \le b_i$ 且 $c_j \le c_i$ 的 $j$ 的数量。

对于 $d \in [0, n)$,求 $f(i) = d$ 的 $i$ 的数量。

数据范围:$1 \le n \le 10 ^ 5$,$1 \le a_i, b_i, c_i \le 2 \times 10 ^ 5$。


Solution

如果有重复的处理起来就比较麻烦,于是我们先去重,记录每个属性有多少朵花。

这题就是一个裸的 $\text{CDQ}$ 分治。我们对第一维 $S_i$ 排序,这样可以忽略第一维的影响;对第二份进行分治,合并时我们用树状数组记录每个 $M_i$ 出现的次数,和统计逆序对类似的方法计算左区间对右区间的贡献。

时间复杂度:$\mathcal O(n\log^2 n)$。


Code

#include <cstdio>
#include <algorithm>

const int N = 2e5 + 5;

int n, k, f[N];

struct Data {
    int x, y, z, idx, cnt, ans;
    bool operator!=(const Data &b) const {
        return x != b.x || y != b.y || z != b.z;
    }
} a[N], t[N];

struct BIT {
    int b[N];
    void add(int x, int v) {
        for (; x <= k; x += x & -x) b[x] += v;
    }
    int query(int x) {
        int ans = 0;
        for (; x; x ^= x & -x) ans += b[x];
        return ans;
    }
} bit;

void CDQ(int l, int r) {
    if (l == r) return;
    int m = (l + r) >> 1;
    CDQ(l, m), CDQ(m + 1, r);
    std::merge(a + l, a + m + 1, a + m + 1, a + r + 1, t + l, [](Data a, Data b) {
        return a.y < b.y;
    });
    std::copy(t + l, t + r + 1, a + l);
    for (int i = l; i <= r; i++) {
        if (a[i].idx <= m) {
            bit.add(a[i].z, a[i].cnt);
        } else {
            a[i].ans += bit.query(a[i].z);
        }
    }
    for (int i = l; i <= r; i++) {
        if (a[i].idx <= m) bit.add(a[i].z, -a[i].cnt);
    }
}
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z);
    }
    std::sort(a + 1, a + n + 1, [](Data a, Data b) {
        return a.x == b.x ? a.y == b.y ? a.z < b.z : a.y < b.y : a.x < b.x;
    });
    int tot = 0;
    for (int i = 1; i <= n; i++) {
        if (!tot || a[i] != a[i - 1]) a[++tot] = a[i], a[tot].idx = tot;
        a[tot].cnt++;
    }
    CDQ(1, tot);
    for (int i = 1; i <= tot; i++) f[a[i].ans + a[i].cnt - 1] += a[i].cnt;
    for (int i = 0; i < n; i++) printf("%d\n", f[i]);
    return 0;
}

发表评论