您的位置:首页 > 其它

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

2017-07-16 14:57 561 查看

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: