HYSBZ - 3262 陌上花开 (CDQ分治)

题目链接:https://cn.vjudge.net/problem/HYSBZ-3262

有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。

现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。

定义一朵花A比另一朵花B要美丽,当且仅Sa>=Sb,Ca>=Cb,Ma>=Mb。

显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。

Input

第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。

以下N行,每行三个整数xi, yi, zi (1 <= si, ci, mi <= K),表示第i朵花的属性

Output

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

解析:CDQ分治,先对x从小到大排序,再对y从小到大排序,再对z从小到大排序

一维排序,二维分治,第三维树状数组

注意去重,

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 3e5 + 30;
struct node{
    int x, y, z;
    int val, id;
}a[maxn], q[maxn], tmp[maxn];
int num[maxn], book[maxn], sum[maxn];
int ans[maxn];
bool cmp(node x, node y){
    if(x.x != y.x) return x.x < y.x;
    else if(x.y != y.y) return x.y < y.y;
    return x.z < y.z;
}

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

void add(int x, int val){
    if(x == 0) return;
    while(x < maxn) {
        sum[x]+=val;
        x += lowbit(x);
    }
}

void del(int x) {
    if(x == 0) return;
    while(x < maxn) {
        sum[x] = 0;
        x += lowbit(x);
    }
}

int query(int x){
    int ans = 0;
    while(x) {
        ans += sum[x];
        x -= lowbit(x);
    }
    return ans;
}

void CDQ(int l, int r){
    if(r - l <= 1) {
        ans[q[l].id] = book[q[l].id] - 1;
        return;
    }
    int mid = l + r >> 1;
    CDQ(l, mid);
    CDQ(mid, r);
    int t1 = l, t2 = mid, cnt = 0;
    while(t1 < mid && t2 < r){
        if(q[t1].y <= q[t2].y){
            add(q[t1].z, q[t1].val);
            tmp[cnt++] = q[t1++];
        }
        else {
            ans[q[t2].id] += query(q[t2].z);
            tmp[cnt++] = q[t2++];
        }
    }
    while(t1 < mid){
        tmp[cnt++] = q[t1++];
    }
    while(t2 < r){
        ans[q[t2].id] += query(q[t2].z);
        tmp[cnt++] = q[t2++];
    }
    for(int i = 0; i < cnt; i++) {
        q[i + l] = tmp[i];
        del(tmp[i].z);
    }
}
int main()
{
    int n, k;
    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);
        num[i] = 0;
        ans[i] = 0;
        book[i] = 0;
    }
    sort(a + 1, a + n + 1, cmp);
    book[0] = num[0] = ans[0] = 0;
    int len = 0;
    for(int i = 1; i <= n; i++) {
        if(a[i].x == a[i - 1].x && a[i].y == a[i - 1].y && a[i].z == a[i - 1].z) {
            book[q[len - 1].id]++;
            q[len - 1].val++;
            continue;
        }
        book[i] = 1;
        q[len].id = i;
        q[len].x = a[i].x;
        q[len].y = a[i].y;
        q[len].z = a[i].z;
        q[len].val = 1;
        len++;
    }
    CDQ(0, len);
    for(int i = 1; i <= n; i++) num[ans[i]]+=book[i];
    for(int i = 0; i < n; i++) printf("%d\n", num[i]);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值