## [$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 #include #include #include 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; } ```