CDQ分治--模板 BZOJ 3262--陌上花开【三维偏序】

来源:互联网 发布:java类的主方法是啥 编辑:程序博客网 时间:2024/05/22 06:30

Description

有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。

题解

这是典型的三维偏序的问题,可以套高级数据结构,当然,更简便的做法是用CDQ分治。

什么是CDQ分治

CDQ分治是陈丹琦大神(Orz%%%)在08提出来的,所以就叫CDQ分治。

我们知道,有一些动态修改的问题,需要各种数据结构,如果没有强制在线的话,就可以用CDQ分治将其转化成静态的问题。

CDQ分治是对操作序列分治:
1.将序列[l,r]分成两半[l,mid]和[mid+1,r];
2.分别处理两半序列中的操作;
3.考虑[l,mid]对[mid+1,r]的影响;

以此题为例

考虑如果是二维偏序我们怎么做?肯定是按照其中一维排序,剩下的交给树状数组,所以三位偏序也一样,先按其中一维排序,然后剩下的交给树套树(不会啊),但是我们不想写树套树,所以就用CDQ分治来处理剩下的两维。

考虑到既然已经按照x排过序了,那么前半段序列中的x一定后半段序列的x,所以我们分别对两段序列排序并不会造成什么影响(两段中的答案都已经各自统计过了),那么我们就将他们分别按照y排序,然后像二维偏序那样用树状数组就可以了(这里要注意,清树状数组时不能用memset,不然会超时,清的时候只能清修改过的,不然复杂度不对)。

代码

#include<cstdio>#include<cstring>#include<algorithm>#define maxn 100006#define maxm 200006#define lowbit(x) (x&-x)using namespace std;inline char nc(){    static char buf[100000],*i=buf,*j=buf;    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;}inline int _read(){    char ch=nc();int sum=0;    while(!(ch>='0'&&ch<='9'))ch=nc();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();    return sum;}struct point{    int x,y,z,p;    bool operator ==(const point&b)const{return x==b.x&&y==b.y&&z==b.z;}    bool operator <(const point&b)const{return y<b.y||(y==b.y&&z<b.z);}}a[maxn],c[maxn];int n,m,ans[maxn],opt[maxm];bool cmp(point x,point y){return x.x<y.x||(x.x==y.x&&(x.y<y.y||(x.y==y.y&&x.z<y.z)));}void put(int x,int y){for(;x<=m;x+=lowbit(x))opt[x]+=y;}int get(int x){    int sum=0;    for(;x;x-=lowbit(x))sum+=opt[x];    return sum;}void clear(int x){for(;x<=m;x+=lowbit(x))opt[x]=0;}void cdq(int l,int r){    if(l>=r)return;    int mid=(l+r)>>1;    cdq(l,mid);cdq(mid+1,r);    int i=l;    for(int j=mid+1;j<=r;j++){        while(i<=mid&&a[i].y<=a[j].y)put(a[i].z,1),i++;        a[j].p+=get(a[j].z);    }    for(int i=l;i<=mid;i++)clear(a[i].z);    for(int i=l;i<=r;i++)c[i]=a[i];    i=l;int j=mid+1;    for(int k=l;k<=r;k++) if(j>r||((i<=mid&&c[i]<c[j])))a[k]=c[i++];                                                   else a[k]=c[j++];}int main(){    freopen("cdq.in","r",stdin);    freopen("cdq.out","w",stdout);    n=_read();m=_read();    for(int i=1;i<=n;i++) a[i].x=_read(),a[i].y=_read(),a[i].z=_read();    sort(a+1,a+1+n,cmp);    cdq(1,n);    sort(a+1,a+1+n,cmp);    int i=1;    while(i<=n){        int j=i,Max=0;        while(j<=n&&a[i]==a[j])Max=max(Max,a[j++].p);        ans[Max]+=j-i;i=j;    }    for(int i=0;i<n;i++)printf("%d\n",ans[i]);    return 0;}
原创粉丝点击