陌上花开 模板 三维偏序
题目描述
有(n)朵花,每朵花有三个属性:花形((s))、颜色((c))、气味((m)),用三个整数表示。
现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花(A)比另一朵花(B)要美丽,当且仅$ Sa geq Sb,Ca geq Cb,Ma geq Mb$。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
输入格式
第一行为(N,K (1 <= N <= 100,000, 1 <= K <= 200,000 )), 分别表示花的数量和最大属性值。
以下(N)行,每行三个整数(si, ci, mi (1 <= si, ci, mi <= K)),表示第(i)朵花的属性
输出格式
包含(N)行,分别表示评级为(0...N-1)的每级花的数量。
样例
样例输入
10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
样例输出
3
1
3
0
1
0
1
0
0
1
分析
(CDQ)分治套数状数组
代码
#include<cstdio>
#include<algorithm>
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5;
struct asd{
int a,b,c,id,cnt;
}jl[maxn],f[maxn];
bool cmp1(asd aa,asd bb){
if(aa.a==bb.a && aa.b==bb.b) return aa.c<bb.c;
if(aa.a==bb.a) return aa.b<bb.b;
return aa.a<bb.a;
}
bool cmp2(asd aa,asd bb){
if(aa.b==bb.b) return aa.c<bb.c;
return aa.b<bb.b;
}
int n,k,ans[maxn],tr[maxn],anss[maxn];
int lb(int xx){
return xx&-xx;
}
void ad(int wz,int val){
for(int i=wz;i<maxn;i+=lb(i)){
tr[i]+=val;
}
}
int qh(int wz){
int nans=0;
for(int i=wz;i>0;i-=lb(i)){
nans+=tr[i];
}
return nans;
}
void solve(int l,int r){
if(l==r) return;
int mids=(l+r)>>1;
solve(l,mids);
solve(mids+1,r);
std::sort(f+l,f+mids+1,cmp2);
std::sort(f+mids+1,f+r+1,cmp2);
int now=l;
for(int i=mids+1;i<=r;i++){
while(f[now].b<=f[i].b && now<=mids){
ad(f[now].c,f[now].cnt);
now++;
}
ans[f[i].id]+=qh(f[i].c);
}
for(int i=now-1;i>=l;i--) ad(f[i].c,-f[i].cnt);
}
int main(){
n=read(),k=read();
for(int i=1;i<=n;i++){
jl[i].a=read(),jl[i].b=read(),jl[i].c=read();
jl[i].id=i;
}
std::sort(jl+1,jl+1+n,cmp1);
int nn=n,js=0;
n=0;
for(int i=1;i<=nn;i++){
js++;
if(jl[i].a!=jl[i+1].a || jl[i].b!=jl[i+1].b || jl[i].c!=jl[i+1].c){
f[++n]=jl[i];
f[n].cnt=js;
js=0;
}
}
solve(1,n);
for(int i=1;i<=n;i++){
anss[ans[f[i].id]+f[i].cnt-1]+=f[i].cnt;
}
for(int i=0;i<nn;i++){
printf("%d
",anss[i]);
}
return 0;
}