陌上花开 bzoj3262 CDQ分治套树状数组 三维偏序问题

这道题应该是学CDQ分治的必做题也是CDQ分治一个很好的运用 三维偏序问题
题意是给你 n n 个三元组(x,y,z) 对于每个三元组 i i 统计满足xj<=xi,yj<=yi,zj<=zi j j 的个数

对于第一维的限制 我们可以直接 std::sort 解决, 第二维我们可以用CDQ分治来进行计算, 最后再把满足第三维条件的数加入到树状数组即可 复杂度 O(nlog2n) O ( n l o g 2 n ) 具体实现见代码

notice: n o t i c e : 树状数组每次分治使用完一定要清空, 并且要记得对三元组进行去重.
题目链接

#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define mid ((l + r) >> 1)

using namespace std;

const int maxn = 2e5 + 10;
int n, k, ans[maxn], vis[maxn], m;

struct node
{
    int x, y, z, rk;
    bool operator < (const node T)
    {
        if(x == T.x && y == T.y)
            return z < T.z;
        if(x == T.x)
            return y < T.y;
        return x < T.x;
    }
}A[maxn], tmp[maxn];

namespace Fenwick_Tree
{
    int s[maxn];
    int lowbit(int x)
    {
        return x & -x;
    }
    void update(int x, int y)
    {
        while(x <= k)
        {
            s[x] += y;
            x += lowbit(x);
        }
    }
    int query(int x)
    {
        int res = 0;
        while(x)
        {
            res += s[x];
            x -= lowbit(x);
        }
        return res;
    }
}

void CDQ(int l, int r)
{
    if(l != r)
    {
        CDQ(l, mid), CDQ(mid + 1, r);
        int t = l, t1 = l, t2 = mid + 1;
        while(t1 <= mid && t2 <= r)
        {
            if(A[t1].y <= A[t2].y)
            {
                Fenwick_Tree::update(A[t1].z, 1);
                vis[t] = 1;
                tmp[t ++] = A[t1 ++];
            }
            else
            {
                A[t2].rk += Fenwick_Tree::query(A[t2].z);
                tmp[t ++] = A[t2 ++];
            }
        }
        while(t1 <= mid)
            tmp[t ++] = A[t1 ++];
        while(t2 <= r)
        {
            A[t2].rk += Fenwick_Tree::query(A[t2].z);
            tmp[t ++] = A[t2 ++];
        }
        For(i, l, r)
        {
            A[i] = tmp[i];
            if(vis[i])
            {
                vis[i] = 0;
                Fenwick_Tree::update(A[i].z, -1);
            }
        }
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("3262.in", "r", stdin);
    freopen("3262.out", "w", stdout);
#endif
    scanf("%d%d", &n, &k);
    For(i, 1, n)
        scanf("%d%d%d", &A[i].x, &A[i].y, &A[i].z);
    sort(A + 1, A + n + 1);
    CDQ(1, n);
    for(int i = n; i >= 1; -- i)
        if(A[i].x == A[i - 1].x && A[i].y == A[i - 1].y && A[i].z == A[i - 1].z)
            A[i - 1].rk = A[i].rk;
    For(i, 1, n)
        ++ ans[A[i].rk];
    For(i, 0, n - 1)
        printf("%d\n", ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值