• 洛谷P3810-陌上开花(三维偏序, CDQ, 树状数组)


    链接:

    https://www.luogu.org/problem/P3810#submit

    题意:

    一个元素三个属性, x, y, z, 给定求f(b) = {ax <= bx, ay <= by, az <= bz}, a的数量, 求0-(n-1)个数有多少个点满足

    思路:

    三维偏序, CDQ分治, 听说过, 一直想学, 先写板子题, 二维偏序就属性减到连个,搞一下.
    CDQ的思想就是先对第一维排序, 左边的可以给有变贡献, 在分治下去, 同时对第二维排序, 将可用的点的第三维用数据结构维护一下, 挨个统计.

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 2e5+10;
    
    struct Node
    {
        int x, y, z;
        int cnt;
        int ans;
    }a[MAXN], b[MAXN];
    
    int C[MAXN], Res[MAXN];
    int n, k, cnt;
    
    bool CmpX(Node a, Node b)
    {
        if (a.x != b.x)
            return a.x < b.x;
        else if (a.y != b.y)
            return a.y < b.y;
        else
            return a.z < b.z;
    }
    
    bool CmpY(Node a, Node b)
    {
        if (a.y != b.y)
            return a.y < b.y;
        else
            return a.z < b.z;
    }
    
    int Lowbit(int x)
    {
        return x&(-x);
    }
    
    void Update(int pos, int val)
    {
        while (pos <= k)
        {
            C[pos] += val;
            pos += Lowbit(pos);
        }
    }
    
    int Query(int pos)
    {
        int ans = 0;
        while (pos > 0)
        {
            ans += C[pos];
            pos -= Lowbit(pos);
        }
        return ans;
    }
    
    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, CmpY);
        sort(a+mid+1, a+r+1, CmpY);
        int i = l, j = mid+1;
        while (j <= r)
        {
            while (i <= mid && a[j].y >= a[i].y)
                Update(a[i].z, a[i].cnt), i++;
            a[j].ans += Query(a[j].z);
            j++;
        }
        for (int z = l;z < i;z++)
            Update(a[z].z, -a[z].cnt);
    }
    
    int main()
    {
        scanf("%d%d", &n, &k);
        for (int i = 1;i <= n;i++)
            scanf("%d%d%d", &b[i].x, &b[i].y, &b[i].z);
        sort(b+1, b+1+n, CmpX);
        a[1] = b[1];
        a[1].cnt = 1;
        cnt = 1;
        for (int i = 2;i <= n;i++)
        {
            if (b[i].x != a[cnt].x || b[i].y != a[cnt].y || b[i].z != a[cnt].z)
                a[++cnt] = b[i], a[cnt].cnt = 1;
            else
                a[cnt].cnt++;
        }
        CDQ(1, cnt);
        for (int i = 1;i <= cnt;i++)
            Res[a[i].ans+a[i].cnt-1] += a[i].cnt;
        for (int i = 0;i < n;i++)
            printf("%d
    ", Res[i]);
    
        return 0;
    }
    
  • 相关阅读:
    2020.08.28【周报】
    区间合并【排序、栈】
    1042 数字0-9的数量【解题数分DP】
    asp.net数据分页方法
    纯css面板插件,自适应,多样式
    c#winform图表控件使用示例
    使用妹子UI开发的体验分享
    阿里云储存代码整理(由三卷天书整理)
    测试程序的时候用到写参数或者错误日志的几个方法,用来方便发现错误
    fineUI表格控件各属性说明
  • 原文地址:https://www.cnblogs.com/YDDDD/p/11529560.html
Copyright © 2020-2023  润新知