BZOJ3262: 陌上花开【三维偏序】
程序员文章站
2022-05-14 18:55:51
...
题目描述:
有n朵花,每朵花有三个属性:花形(s)、颜色©、气味(m),用三个整数表示。
现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花A比另一朵花B要美丽,当且仅Sa>=Sb,Ca>=Cb,Ma>=Mb。
显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。
以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性
题目分析:
三维偏序模板。
但是要注意的是花的三个属性都相同的时候,在cdq分治中计算贡献时的顺序问题,如果当cdq的那一维相同时要先将所有的值加到树状数组中再来统计,如果不想加这个特判,就在外面把相同的合并,加贡献的时候注意加的是个数。
第一维排序,第二维cdq,第三维树状数组(这是比较方便的写法,当然还有很多种写法)。
这里的cdq可以只带两个参数表示操作区间,然后对第二维进行归并排序。
也可以带四个参数表示第二维的权值区间和操作区间,相当于用权值的mid来划分操作,就不用归并了。(虽然代码反而变长了。。)
Code:
#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn 200005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
int n,m,Q,N,ans[maxn],num[maxn];
int arr[maxn];
void upd(int i,int d){for(;i<=N;i+=i&-i) arr[i]+=d;}
int qsum(int i){int s=0;for(;i;i-=i&-i) s+=arr[i];return s;}
struct node{
int x,y,z,ans,c; node(){}
node(int x,int y,int z,int ans,int c):x(x),y(y),z(z),ans(ans),c(c){}
bool operator < (const node &p)const{return x==p.x?y==p.y?z<p.z:y<p.y:x<p.x;}
}a[maxn],b[maxn];
void solve(int l,int r,int ql,int qr){
if(ql>=qr) return;
if(l==r){
for(int i=ql;i<=qr;i++) a[i].ans+=qsum(a[i].z),upd(a[i].z,a[i].c);
for(int i=ql;i<=qr;i++) upd(a[i].z,-a[i].c);
return;
}
int mid=(l+r)>>1,lp=ql,rp;
for(int i=ql;i<=qr;i++)
if(a[i].y<=mid) b[lp++]=a[i],upd(a[i].z,a[i].c);
else a[i].ans+=qsum(a[i].z);
rp=lp;
for(int i=ql;i<=qr;i++)
if(a[i].y<=mid) upd(a[i].z,-a[i].c);
else b[rp++]=a[i];
for(int i=ql;i<=qr;i++) a[i]=b[i];
solve(l,mid,ql,lp-1),solve(mid+1,r,lp,qr);
}
int main()
{
read(n),read(N);
for(int i=1;i<=n;i++) read(b[i].x),read(b[i].y),read(b[i].z),b[i].c=1;
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
if(b[i].x!=b[i-1].x||b[i].y!=b[i-1].y||b[i].z!=b[i-1].z) a[++m]=b[i];
else a[m].c++;
solve(1,N,1,m);
for(int i=1;i<=m;i++) num[a[i].ans+a[i].c-1]+=a[i].c;
for(int i=0;i<n;i++) printf("%d\n",num[i]);
}