BZOJ_3262_陌上花开_CDQ分治+树状数组

BZOJ_3262_陌上花开_CDQ分治+树状数组

Description

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

Input

第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。
以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性

Output

包含N行,分别表示评级为0...N-1的每级花的数量。

Sample Input

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

Sample Output

3
1
3
0
1
0
1
0
0
1
 

学习一下CDQ分治。
CDQ分治的思想是分治成两部分,先处理左部分再处理右部分,再考虑左对右的影响。
首先按第一维排序,再把三维都相等的合并。
然后分治,相当于把第二维当成时间,使用归并排序。
归并时如果在左边就把它的第三维加到树状数组里,如果在右边就把答案加上左边的贡献。
最后清一下树状数组。
注意输出时要按照读入的顺序输出。
 
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
struct A {
    int x,y,z,cnt,num;
    bool operator == (const A &u) const {
        return x==u.x&&y==u.y&&z==u.z;
    }
}a[N],v[N],tmp[N];
bool cmp(const A &u,const A &v) {
    if(u.x==v.x&&u.y==v.y) return u.z<v.z;
    if(u.x==v.x) return u.y<v.y;
    return u.x<v.x;
}
int n,c[N*2],maxvalue,ans[N];
void fix(int x,int v) {
    for(;x<=maxvalue;x+=x&(-x)) c[x]+=v;
}
int inq(int x) {
    int re=0;
    for(;x;x-=x&(-x)) re+=c[x];
    return re;
}
void solve(int l,int r) {
    if(l==r) return;
    int mid=(l+r)>>1,i=l,j=mid+1,p=l;
    solve(l,mid); solve(mid+1,r);
    while(i<=mid&&j<=r) {
        if(v[i].y<=v[j].y) fix(v[i].z,v[i].cnt),tmp[p++]=v[i++];
        else tmp[p]=v[j],tmp[p++].num+=inq(v[j++].z);
    }
    while(i<=mid) {
        fix(v[i].z,v[i].cnt); tmp[p++]=v[i++];
    }
    while(j<=r) {
        tmp[p]=v[j],tmp[p++].num+=inq(v[j++].z);
    }
    for(i=l;i<=mid;i++) fix(v[i].z,-v[i].cnt);
    for(i=l;i<=r;i++) v[i]=tmp[i];
}
int main() {
    scanf("%d%d",&n,&maxvalue);
    int i;
    for(i=1;i<=n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    sort(a+1,a+n+1,cmp);
    int tot=0;
    a[0].x=423453;
    for(i=1;i<=n;i++) {
        if(!(a[i]==a[i-1])) v[++tot]=a[i];
        v[tot].cnt++;
    }
    solve(1,tot);
    for(i=1;i<=tot;i++) ans[v[i].num+v[i].cnt]+=v[i].cnt;
    for(i=1;i<=n;i++) printf("%d\n",ans[i]);
}

 

posted @ 2018-04-08 08:41  fcwww  阅读(160)  评论(0编辑  收藏  举报