BZOJ 3262 陌上花开(cdq分治,树状数组)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baodream/article/details/82666950

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3262

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分治模板:https://blog.csdn.net/baodream/article/details/82666931

AC代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>

using namespace std;

#define FOU(i,x,y) for(int i=x;i<=y;i++)
#define FOD(i,x,y) for(int i=x;i>=y;i--)
#define MEM(a,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)

const double EXP = 1e-9;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const ll MINF = 0x3f3f3f3f3f3f3f3f;
const double DINF = 0xffffffffffff;
const int mod = 1e9+7;
const int N = 2e5+5;

struct node{
    int x,y,z;
    int id;
}a[N],tmp[N];

int ans[N],cnt[N];   //ans[i]代表比第i个点小的点有多少个
int n,k;             //n代表点的个数,k代表点的范围

bool cmp(node a,node b){
    if(a.x==b.x&&a.y==b.y)
        return a.z<b.z;
    if(a.x==b.x)
        return a.y<b.y;
    return a.x<b.x;
}

int tree[N]; //tree数组按二进制存,根据n的末尾0的个数存取,树状数组

int lowbit(int x)
{
    return x&(-x);
}

int Query(int x)  //返回1到x的前缀和
{
    int res=0;
    while(x)
    {
        res+=tree[x];
        x-=lowbit(x);
    }
    return res;
}

void Add(int x,int v)  //实现a[x]+v;
{
    while(x<=k)        //注意这里是小于等于k,不是n,k是数据范围
    {
        tree[x]+=v;
        x+=lowbit(x);
    }
}

void clearr(int x){
    while(x<=k){
        if(tree[x]==0)
            break;
        tree[x]=0;
        x+=lowbit(x);
    }
}

void cdq(int l,int r){
     //cout<<"l "<<l<<" r "<<r<<endl;
     if(l>=r)
        return ;
    int mid = l+r>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    int p=l,q=mid+1,k=l;
    while(p<=mid&&q<=r){
        if(a[p].y<=a[q].y){
            Add(a[p].z,1);
            tmp[k++] = a[p++];
        }
        else{
            ans[a[q].id]+=Query(a[q].z);
            tmp[k++] = a[q++];
        }
    }
    while(p<=mid){
        Add(a[p].z,1);
        tmp[k++] = a[p++];
    }
    while(q<=r){
        ans[a[q].id]+=Query(a[q].z);
        tmp[k++] = a[q++];
    }
    for(int i=l;i<=r;i++){
        clearr(a[i].z);
        a[i] = tmp[i];
    }
     /*
    cout<<"*** l "<<l<<" **  r "<<r<<endl;
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    cout<<endl;
    */
}

bool compare(node a,node b){
    if(a.x==b.x&&a.y==b.y&&a.z==b.z)
        return true;
    return false;
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    std::ios::sync_with_stdio(false);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
        a[i].id = i;
    }
    sort(a+1,a+1+n,cmp);    //一维用sort保证,二维归并的时候保证,三维树状数组保证
    node temp = {-1,-1,-1,-1};
    int res = 0;
    for(int i=n;i>=1;i--){       //这里处理一下后面相同的个数,因为分治的时候处理不了后面的
        if(compare(temp,a[i])){
            ans[a[i].id]+=res;
            res++;
        }
        else{
            temp = a[i];
            res=1;
        }
    }
    cdq(1,n);        //cdq分治求答案
    /*for(int i=1;i<=n;i++)
        printf("ans[%d]=%d\n",i,ans[i]);*/
    for(int i=1;i<=n;i++)
        cnt[ans[i]]++;
    for(int i=0;i<n;i++)
        printf("%d\n",cnt[i]);  //cnt[i]是每一级的点的个数
    return 0;
}

猜你喜欢

转载自blog.csdn.net/baodream/article/details/82666950