ACM复习(6)1144 数星星

Description
天文学家们喜欢观察星星。它们把每颗星星看成一个点,并把每颗星星左下方(即横坐标和纵坐标都不比它大)的星星颗数作为它的等级值。
现给出所有星星(星星个数为N)的坐标,计算并输出指定编号的星星的等级。

注意:不存在相同坐标的星星

输入格式
第一行为N
后N行为编号为1到N的星星的坐标(坐标用整数)
此后是M
后一行是M个星星的编号

N<=100000
M<=1000

坐标范围0<=x,y<=1000000

输出格式
要求依次输出这M个星星的等级,一行一个

输入样例
5
0 0
2 0
3 0
1 1
2 2
2
4 5

输出样例
1
3


解题思路

树状数组的应用,而且是将二维树状数组降到一维,因为x, y的最大值为1000000,开
二维树状数组会爆内存。
怎么降维?先按一个维度(这里选择 x)对数组进行排序,对剩下的一个维度进行树状
数组操作。
操作过程相当于将原数组和维护数组清零,然后不断进行单点更新和区间求和

#include<stdio.h>
#include<stdlib.h>
struct start
{
    int x;
    int y;
    int num;
};

int cmp(const void * a, const void * b);
int lowbit(int n);
void update(int *t, int n);
int sum(int * t, int n);
int max = 0;
int c[1000002] = {0};

int main()
{
    int n, m;
    scanf("%d", &n);
    start start_list[n];
    int q[n], ans[n];
    for(int i = 0; i < n; i ++)
    {
        scanf("%d %d", &start_list[i].x, &start_list[i].y); 
        // 维护数组的index不能出现0,不然lowbit()会出错
        start_list[i].x ++;
        start_list[i].y ++;
        max = max > start_list[i].y ? max : start_list[i].y;
        // 编号从1开始
        start_list[i].num = i + 1;
    }
    scanf("%d", &m);
    for(int i = 0; i < m; i ++)
        scanf("%d", &q[i]);
    //x进行排序
    qsort(start_list, n, sizeof(start), cmp);
    for(int i = 0; i < n; i ++)
    {
        // 因为已排过序,可以保证先操作的都是x小的星星
        ans[start_list[i].num] = sum(c, start_list[i].y);
        update(c, start_list[i].y);
    }
    for(int i = 0; i < m; i++)
        printf("%d\n", ans[q[i]]);

    return 0;
}

int cmp(const void * a, const void * b)
{
    start * a2 = (start *)a;
    start * b2 = (start *)b;
    if(a2->x < b2->x)
        return -1;
    else if(a2-> x == b2->x)
    {
        if(a2-> y < b2->y)
            return -1;
        else
            return 1;
    }
    else
        return 1;   
}   

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

void update(int *t, int n)
{
    while(n <= max)
    {
        c[n] += 1;
        n += lowbit(n);
    }
}   

int sum(int * t, int n)
{
    int s = 0;
    while(n > 0)
    {
        s += c[n];
        n -= lowbit(n);
    }
    return s;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值