ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

陌上花开(三维偏序 CDQ分治)

2019-07-10 18:55:22  阅读:194  来源: 互联网

标签:偏序 ch 标记 int 陌上 mid CDQ 排序


题目描述

有 n 个元素,第 i 个元素有 ai​、bi​、ci​ 三个属性,设 f(i) 表示满足 aj​≤ai​ 且 bj​≤bi​ 且cj​≤ci​ 的 j 的数量。

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

思路

对于二维偏序,我们可以对第一维排序,然后用按顺序树状数组维护第二维即可。考虑另一种方式,

在处理第二维时,将这些数分成两半,左边的数打标记,接着再按第二维排序,考虑左边对右边的贡

献,就是没打标记的数前打了标记的数,这个直接从头for一遍即可,遇到标记就cnt++,没标记就记

录答案,对于自己那一边的数自己的贡献,递归处理。

对于三维偏序,我们可以用类似的方法,只是在遇到带标记的数时加入树状数组,没标记就查询答案。

代码

与上面思路略有不同,在回归时分别对左右两边按第二维排序,左右两边第一维的相对大小仍存在,

用双指针在两边移动,将左边的数加入树状数组,再统计贡献。

细节

  1. 去重,对于重复的三元组,并不是每个三元组都能统计到对方,所以要去重并记录个数。
  2. 在CDQ排序时两个端点。
  3. 递归在每层最后要清零,但不能memset会超时,需要一个一个加负的。
  4. 统计答案时,a[i].w-1是统计与自己重复的数
  5. 去重时要for到n,不然最后一个数不能放进a数组
  6. 按x排序时不能单纯按x排,因为这样就不能去重
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005,maxk=200005;
    int n,k,_n;
    int tr[maxk<<1],cnt[maxn];
    struct point {
        int x,y,z,w,ans;
    }a[maxn],b[maxn];
    
    template<class T>inline void read(T &x){
        x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    }
    
    bool cmp1(point a,point b){
        if(a.x==b.x){
            if(a.y==b.y) return a.z<b.z;
            return a.y<b.y;
        }
        return a.x<b.x;
    }
    
    bool cmp2(point a,point b){
        if(a.y==b.y) return a.z<b.z;
        return a.y<b.y;
    }
    
    void add(int pos,int v){
        for(int i=pos;i<=k;i+=i&-i) tr[i]+=v;
    }
    
    int sum(int pos){
        int ret=0;
        for(int i=pos;i;i-=i&-i) ret+=tr[i];
        return ret;
    }
    
    void cdq(int l,int r){
        if(l==r) return ;
        int mid=(l+r)>>1;
        cdq(l,mid);
        cdq(mid+1,r);
        sort(a+l,a+mid+1,cmp2);
        sort(a+mid+1,a+r+1,cmp2);
        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].w);
                j++;
            }
            a[i].ans+=sum(a[i].z);
        }
        for(i=l;i<j;i++) add(a[i].z,-a[i].w);
    }
    
    int main(){
        read(n);read(k);
        for(int i=1;i<=n;i++) read(b[i].x),read(b[i].y),read(b[i].z);
        sort(b+1,b+n+1,cmp1);
        int c=0;
        for(int i=1;i<=n;i++){
            c++;
            if(b[i].x!=b[i+1].x||b[i].y!=b[i+1].y||b[i].z!=b[i+1].z)
             a[++_n]=b[i],a[_n].w=c,c=0;
        }
        cdq(1,_n);
        for(int i=1;i<=_n;i++) cnt[a[i].ans+a[i].w-1]+=a[i].w;
        for(int i=0;i<n;i++) printf("%d\n",cnt[i]);
    }

     

标签:偏序,ch,标记,int,陌上,mid,CDQ,排序
来源: https://www.cnblogs.com/sto324/p/11165791.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有