zoukankan      html  css  js  c++  java
  • P3810 【模板】三维偏序(陌上花开)(CDQ分治)

    题目背景

    这是一道模板题

    可以使用bitset,CDQ分治,K-DTree等方式解决。

    题目描述

    有 nn 个元素,第 ii 个元素有 a_iaib_ibic_ici 三个属性,设 f(i)f(i) 表示满足 a_j leq a_iajai 且 b_j leq b_ibjbi 且 c_j leq c_icjci 的 jj 的数量。

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

    输入格式

    第一行两个整数 nn、kk,分别表示元素数量和最大属性值。

    之后 nn 行,每行三个整数 a_iaib_ibic_ici,分别表示三个属性值。

    输出格式

    输出 nn 行,第 d + 1d+1 行表示 f(i) = df(i)=d 的 ii 的数量。

    输入输出样例

    输入 #1
    10 3
    3 3 3
    2 3 3
    2 3 1
    3 1 1
    3 1 2
    1 3 1
    1 1 2
    1 2 2
    1 3 2
    1 2 1
    输出 #1
    3
    1
    3
    0
    1
    0
    1
    0
    0
    1

    说明/提示

    1 leq n leq 100000, 1 leq k leq 2000001n100000,1k200000

    题解:初学习CDQ分治, 拿来这道三维偏序模板题练练手, 定义f(i)代表 a[j].x <= a[i].x && a[j].y <= a[i].y && a[j].z <= a[i].z 的j的个数.

    对应 k = [0,n-1] 输出有多少个i 满足f(i) = k,分别输出. 

     
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 200010;
    ll c[maxn],n,k,cnt[maxn];
    int lowbit(int x){return x & (-x);}
    void add(int pos,int x){
        for(int i = pos;i <= k;i += lowbit(i)){
            c[i] += x;
        }
    }
    ll query(int pos){
        ll sum = 0;
        for(int i = pos; i >= 1;i -= lowbit(i)){
            sum += c[i];
        }
        return sum;
    }
    struct node{
        int x,y,z,cnt,ans;
        bool operator != (const node w)const{ // 重载!=符号,用来判断两个结构体信息是否相同,只判断前三个信息就够了
            if(x != w.x || y != w.y || z != w.z)return 1;//为1代表不等
            else return 0;
        }
    }b[maxn],a[maxn];
    int cmpx(node a,node b){//按x排序
        if(a.x != b.x)return a.x < b.x;
        if(a.y != b.y)return a.y < b.y;
        return a.z < b.z;
    }
    int cmpy(node a,node b){//按y排序
        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) / 2;
        cdq(l,mid),cdq(mid+1,r);
        sort(a + l,a + 1 + mid,cmpy);
        sort(a + mid + 1,a + r + 1,cmpy);
        int i = mid + 1,j = l;
        for(;i <= r;i++){
            while(a[j].y <= a[i].y && j <= mid){
                add(a[j].z,a[j].cnt),j++;
            }
            a[i].ans += query(a[i].z);
        }
        for(int i = l;i < j;i++)add(a[i].z,-a[i].cnt);//这一段区间处理完后对树状数组清零
    }
    int main()
    {
        cin >> n >> k;
        for(int i = 1;i <= n;i++){
            cin >> b[i].x >> b[i].y >> b[i].z;
        }
        sort(b+1,b+1+n,cmpx);
        int w = 0,top = 0;
        for(int i = 1;i <= n;i++){
            w++;
            if(b[i] != b[i+1]){
                a[++top] = b[i];
                a[top].cnt = w;
                w = 0;
            }
        }
        cdq(1,top);
        for(int i = 1;i <= n;i++){//f(i)的值为a[i].ans + a[i].cnt - 1, 因为计算是去重了的
            cnt[a[i].ans + a[i].cnt - 1] += a[i].cnt;//每个a[i] 都满足条件,加上a[i]出现的次数
        }
        for(int i= 0;i < n;i++)cout << cnt[i] << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ.3990.[SDOI2015]排序(DFS)
    BZOJ.1040.[ZJOI2008]骑士(树形DP)
    BZOJ.2246.[SDOI2011]迷宫探险(DP 记忆化搜索 概率)
    BZOJ.3209.花神的数论题(数位DP)
    UVA.1640.The Counting Problem / BZOJ.1833.[ZJOI2010]数字计数(数位DP)
    HDU.3652.B-number(数位DP)
    BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)
    BZOJ.4832.[Lydsy1704月赛]抵制克苏恩(期望DP)
    BZOJ.1025.[SCOI2009]游戏(背包DP)
    BZOJ.3257.树的难题(树形DP)
  • 原文地址:https://www.cnblogs.com/cherish-lin/p/11963128.html
Copyright © 2011-2022 走看看