CDQ分治--模板 BZOJ 3262--陌上花开【三维偏序】
程序员文章站
2022-05-14 18:37:45
...
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一定
代码
#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;
}
推荐阅读
-
陌上花开 HYSBZ - 3262 三维偏序问题 CDQ分治+树状数组
-
BZOJ 3262: 陌上花开 (cdq分治,三维偏序)
-
bzoj 3262 :陌上花开 (cdq分治 三维偏序)
-
【bzoj3262】陌上花开(cdq分治解决三维偏序问题)一些总结
-
BZOJ - 3262 陌上花开 CDQ分治 三维偏序
-
BZOJ3262: 陌上花开【三维偏序】
-
BZOJ 3262 陌上花开 三维偏序,CDQ分治
-
三维偏序(陌上花开)---洛谷P3810&&BZOJ3262(cdq分治--归并排序+树状数组)
-
P3810 -三维偏序(陌上花开)cdq-分治
-
Luogu P3810 【模板】三维偏序(陌上花开) CDQ分治 树状数组