POJ 2352 Stars

\(POJ\) \(2352\) \(Stars\)

一、题目大意

给出\(n\)个点坐标, 按照\(y\)升序的顺序, 若\(y\)相同, 则按照\(x\)升序的顺序. (不用我们自己排序,是\(y,x\)由小到大的顺序给出的坐标)
一个点坐标小于另一个点坐标的含义是, 横纵坐标都不大于另一个点坐标(保证没有两个点坐标完全相同).
对于给出的\(n\)个点中, 定义该点等级为: 小于该点的所有坐标之和. (左下角星星的个数)
问: 对于\(0 \sim n-1\)的所有等级, 输出有多少个点坐标为该等级.

二、解题思路

乍一看好像是二维树状数组,但是本题降低了难度,对于输入是按照:\(Y\)的升序给出坐标,如果\(Y\)相同,则按照\(X\)的升序给出。

:不是应该声明个结构体,然后让我们排序后再捋着来计算的吗?良心发现吗?还是有什么新的企图??

那么输入第\(i\)颗星星的坐标时,小于等于\(X[i]\),小于等于\(Y[i]\),即左下角的星星已经全部出现了,且\(Y\)按照升序给出,因此,可以忽略\(Y\)坐标,只需要找到小于等于\(X[i]\)的星星数量就是星星的级数。

设定数组\(cnt[x]\),表示\(X\)坐标为\(x\)的星星个数。
找小于等于\(X[i]\)的星星,即找前缀和\(c[1] \sim c[X[i]]\)

:题目下标从\(0\)开始,而树状数组不能有下标为\(0\)的情况,所以整体右移动一位。

二、实现代码

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 32010;
int cnt[N];

// 树状数组模板
#define lowbit(x) (x & -x)
typedef long long LL;
int c[N];
void add(int x, int v) {
    while (x < N) c[x] += v, x += lowbit(x);
}
LL sum(int x) {
    LL res = 0;
    while (x) res += c[x], x -= lowbit(x);
    return res;
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int x, y;
        scanf("%d %d", &x, &y); // 这里的y没有用到,想想也是,因为是扫描线是从下向上的,与y的具体值无关
        x++;                    // 树状数组存储从1开始, 所有x映射都+1。
        add(x, 1);
        // 查询在x之前有多少个数字,也就是有多少个星星个数
        cnt[sum(x)]++; // 找到了一个左下角有5个星星的,那么5这个桶计数++,这是题意要求的
    }
    // 输出所有等级星星的个数
    for (int i = 1; i <= n; i++) printf("%d\n", cnt[i]);
    return 0;
}

posted @ 2022-05-04 14:45  糖豆爸爸  阅读(32)  评论(0)    收藏  举报
Live2D