|
|
|
|
## [$POJ$ $2352$ $Stars$](http://poj.org/problem?id=2352)
|
|
|
|
|
|
|
|
|
|
### 一、题目大意
|
|
|
|
|
给出$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$的情况,所以整体右移动一位。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 二、实现代码
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
|
|
#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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|