众所周知,三维偏序问题除了树套树还可以用CDQ分治来解决

CDQ分治与一般的分治区别之处在于,CDQ分治将一个问题划分为两个子问题的同时,按照特定的顺序解决子问题,先解决的子问题对后解决的子问题产生贡献。

先来一道模板题,又是陌上花开
题面就是一道裸的三维偏序
用CDQ分治解决本题的流程
1.按x轴对所有点排序,划分为左右两部分
2.递归解决左右子问题
3.因为此时右边半个子问题是不包含左边的贡献的,所以对右边需要额外加上左边子问题的贡献
4.对左半部分的点按照y轴排序
//因为此时左半部分点的x轴位置均在右半部分左侧,所以只需要按照y轴区分贡献
5.此时问题就降维成二维偏序了
//用树状数组维护一下就好了

贴代码

// #pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <vector>
#include <string>
#include <iostream>
#include <list>
#include <cstdlib>
#include <bitset>
#include <assert.h>
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
// char buf[(1 << 21) + 1], * p1 = buf, * p2 = buf;
//#define int long long
#define lowbit(x) (x & (-x))
#define lson root << 1, l, mid
#define rson root << 1 | 1, mid + 1, r
#define pb push_back
typedef unsigned long long ull;
typedef long long ll;
typedef std::pair<int, int> pii;
#define bug puts("BUG")
const long long INF = 0x3f3f3f3f3f3f3f3fLL;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-6;
template <class T>
inline void read(T &x)
{
    int sign = 1;char c = getchar();x = 0;
    while (c > '9' || c < '0'){if (c == '-')sign = -1;c = getchar();}
    while (c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();}
    x *= sign;
}
#ifdef LOCAL
    FILE* _INPUT=freopen("input.txt", "r", stdin);
    // FILE* _OUTPUT=freopen("output.txt", "w", stdout);
#endif
using namespace std;
const int maxn = 1e6 + 10;
struct NODE
{
    int x, y, z, idx, w;
    bool operator < (const NODE& other)const
    {
        if (x != other.x)
            return x < other.x;
        if (y != other.y)
            return y < other.y;
        return z < other.z;
    }
    bool operator == (const NODE& other)const
    {
        return x == other.x && y == other.y && z == other.z;
    }
} f[maxn];
struct BIT
{
    int bit[maxn << 1], up;
    void add(int k, int v)
    {
        for (; k <= up; k += lowbit(k))
            bit[k] += v;
    }

    int query(int k)
    {
        int res = 0;
        for (; k > 0; k -= lowbit(k))
            res += bit[k];
        return res;
    }
} bit;
int ans[maxn], ansout[maxn], a[maxn];
bool cmpy(const NODE& a,const NODE&b)
{
    if (a.y != b.y)
        return a.y <= b.y;
    return a.z < b.z;
}

void cdq(int l, int r)
{
    if (l == r)
        return;
    int mid = l + r >> 1;
    cdq(l, mid);
    cdq(mid + 1, r);
    sort(f + l, f + mid + 1,cmpy);
    sort(f + mid + 1, f + r + 1,cmpy);
    int i = mid + 1, j = l;
    for (; i <= r; ++i)
    {
        while (j <= mid && f[j].y <= f[i].y)
            bit.add(f[j].z, f[j].w), ++j;
        ans[f[i].idx] += bit.query(f[i].z);
    }
    for (i = l; i < j; ++i)
        bit.add(f[i].z, -f[i].w);
}

int main()
{
    int n, k;
    read(n), read(k), bit.up = k;
    for (int i = 1; i <= n; ++i)
        read(f[i].x), read(f[i].y), read(f[i].z), f[i].idx = i;
    sort(f + 1, f + 1 + n);
    int tot = 1;
    f[1].w = 1;
    a[f[1].idx] = f[1].idx;
    for (int i = 2; i <= n; ++i)
    {
        if (f[i] == f[i - 1])
        {}
        else
        {
            f[++tot] = f[i];
        }
        f[tot].w++;
        a[f[i].idx] = f[tot].idx;
    }
    cdq(1, tot);
    for (int i = 1; i <= tot; ++i)
        ans[f[i].idx] += f[i].w;
    for (int i = 1; i <= n; ++i)
    {
        ansout[ans[a[i]] - 1]++;
    }
    for (int i = 0; i < n; ++i)
        printf("%d\n", ansout[i]);
}