题意:大概就是计算每颗星星左下边包括了多少颗星星,这个数值就是level。左下边不包括本身,不超过本身的x,y的坐标,可以等于。问每种level有多少颗星星。
这题,一开始想不到怎么用到树状数组,后来看了一下,发现题目给的数据是已经按x,y排好序的。所以我们可以不用管y的值,为什么呢?
我们一个星星一个星星的读取进来它的坐标,因为它先要把y相等的星星全输出完了,而且是按x递增的方式输出的,然后再会增大y,继续读入之后的星星坐标,
所以我们用树状数组最好了,先看一排的星星坐标,也就是先不管y,只看y值相同的星星坐标的x。设a[i]表示x轴坐标为i的点的level,这个level包括了它本身。
因为x是递增输入的,当一个x输入时,它之后的所有星星的level值肯定都要加一,即x和大于它的a[]数组值都要加一,这是肯定的。这点就是树状数组的最基本应用-单点更新。所以横的x轴处理完了。
那么纵的y轴怎么处理呢?
我们发现,当处理完了一排星星坐标时,下次读入的星星坐标肯定是y增大了,x变没变小不一定,而且我们此时的树状数组里已经存下了之前读入进来的星星的坐标了,那么此时我在y增大的情况下,再读入一个星星坐标,那么这个星星的level是不是就刚好等于它之前已经处理过了的所有a[i](i小于等于这个点的x)的值和了,为什么可以等于?因为你现在还没有对这个点的x的值进行单点更新,故它没有包括自己本身这个点,只是包括了y小于自己的y的x和自己相等的a[x]罢了。所以这里的求a[0]+a[1]+.....+a[x]的和刚好又用到的是树状数组的另一个最基本的应用-区间求和。
所以此题是树状数组的基本应用。
注:此题的x坐标可以为0,而树状数组是从1开始的,所以处理的时候对每个x坐标进行加一即可。输出从level=0,开始。
代码如下:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define N 32001 int C[N]; int num[N]; int T; int Lowbit(int x){ return x&(x^(x-1)); } void add(int pos,int num) { while(pos <= N) {//x最大是N C[pos] += num; pos += Lowbit(pos); } } int Sum(int end) { int sum = 0; while(end > 0) { sum += C[end]; end -= Lowbit(end); } return sum; } int main() { int s, t, i, j, T; while(~scanf("%d",&T)) { memset(C,0,sizeof(C)); memset(num,0,sizeof(num)); for(j = 1; j <= T; j ++) { scanf("%d%d",&s,&t); num[Sum(s+1)]++; add(s+1,1); } for(i = 0; i < T; i ++){ printf("%d\n",num[i]); } } return 0; }