zoukankan      html  css  js  c++  java
  • 三维偏序

    P3810 【模板】三维偏序(陌上花开)

    题目背景

    这是一道模板题

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

    题目描述

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

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

    输入输出格式

    输入格式:

    第一行两个整数(n)(k),分别表示元素数量和最大属性值。

    之后(n)行,每行三个整数(a_i)(b_i)(c_i),分别表示三个属性值。

    输出格式:

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

    说明

    $1 leq n leq 100000, 1 leq k leq 200000 $


    这里采用的是归并排序套树状数组的做法。

    先不考虑重复元素

    首先考虑二维偏序,我们可以对二元组((x,y))(x)为第一关键字,(y)为第二关键字进行排序。然后单独讨论(y)的顺序对(与逆序对相反的一个概念),每个(y)的顺序对数量即为满足题目条件的顺序对数量。这点不难想明白。

    然后类比三维偏序,我们可以对三元组((x,y,z))同样如此做,但统计时并不是(y)的所有顺序对都合法,我们对统计时的(z)维护一权值树状数组,每次查询在顺序对中有多少个(z)小于等于当前的(z)

    考虑重复元素,这个题题意没有明确说明,但每个三元组是不考虑自己的。

    我们先缩点去重,然后统计的时候按数量统计即可


    Code:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N=100010;
    const int M=200010;
    struct node
    {
        int x,y,z,cnt;
        bool friend operator <(node n1,node n2)
        {
            if(n1.x==n2.x)
            {
                if(n1.y==n2.y) return n1.z<n2.z;
                return n1.y<=n2.y;
            }
            return n1.x<n2.x;
        }
    }a[N],d[N],dx[N],tmp[N];
    int n,n_,k;
    void init()
    {
        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);
            a[i].cnt=1;
        }
        sort(a+1,a+1+n_);
        for(int i=1;i<=n_;i++)
        {
            while(d[n].x==a[i].x&&d[n].y==a[i].y&&d[n].z==a[i].z) d[n].cnt++,i++;
            if(i<=n_) d[++n]=a[i];
        }
    }
    int sum[M],ans[N],cnt0[N];
    void add(int x,int delta)
    {
        while(x<=k)
        {
            sum[x]+=delta;
            x+=x&-x;
        }
    }
    int query(int x)
    {
        int s=0;
        while(x)
        {
            s+=sum[x];
            x-=x&-x;
        }
        return s;
    }
    void divide(int l,int r)
    {
        if(l==r) {cnt0[l]+=dx[l].cnt-1;return;}
        int mid=l+r>>1;
        divide(l,mid);
        divide(mid+1,r);
        int pos=l,cnt=l-1;
        for(int i=mid+1;i<=r;i++)
        {
            while(pos<=mid&&dx[pos]<dx[i])
            {
                tmp[++cnt]=dx[pos];
                add(dx[pos].y,dx[pos].cnt);
                pos++;
            }
            tmp[++cnt]=dx[i],cnt0[dx[i].z]+=query(dx[i].y);
        }
        for(int i=l;i<pos;i++)
            add(dx[i].y,-dx[i].cnt);
        while(pos<=mid) tmp[++cnt]=dx[pos++];
        for(int i=l;i<=r;i++)
            dx[i]=tmp[i];
    }
    void work()
    {
        for(int i=1;i<=n;i++)
            dx[i].x=d[i].y,dx[i].y=d[i].z,dx[i].z=i,dx[i].cnt=d[i].cnt;
        divide(1,n);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=dx[i].cnt;j++)
                ans[cnt0[dx[i].z]]++;
        }
        for(int i=0;i<n_;i++)
            printf("%d
    ",ans[i]);
    }
    int main()
    {
        init();
        work();
        return 0;
    }
    
    

    2018.7.15

  • 相关阅读:
    (数据科学学习手札48)Scala中的函数式编程
    Java中的集合(十三) 实现Map接口的Hashtable
    Java中的集合(十二) 实现Map接口的WeakHashMap
    Java中的集合(十一) 实现Map接口的TreeMap
    Java集合(十)实现Map接口的HashMap
    Java集合(九)哈希冲突及解决哈希冲突的4种方式
    Java集合(八)哈希表及哈希函数的实现方式
    Java中的集合(七)双列集合顶层接口------Map接口架构
    Java中的集合(六)继承Collection的Set接口
    Java中的集合(五)继承Collection的List接口
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9315447.html
Copyright © 2011-2022 走看看