题目链接:http://poj.org/problem?id=2352
start 数星星(POJ2352)
题目描述:天文学家时常调查星图,星图在一个平面上表示出所有星星,而且每个星星都有笛卡尔坐标。星星的级别是不在它上面且不在它右面的星星的总数。 天文学家想知道每个星星的级别。
举例来说,看上面的图。 5号星星的级别是3(由 1,2 和 4 号而得)。2 点和 4 号星星的级别是 1. 在这个图里只有一个级别为 0 的星星,两个级别为 1 的星星,一个级别为 2 的星星和一个级别为 3 的星星。你的任务是计算每个级别的星星总数
Input
第一行包含一个数 N (1<=N<=15000)。一下 N 行描述相应的星星(每行两个用空格隔开的整数 X 和 Y, 0<=X,Y<=32000)。平面上每个坐标最多只有一个星星。星星按 Y 的升序排列,Y 相等则按 X 的升序排列
Output
输出包含 N 行,每行一个数。第一行包含级别为 0 的星星的总数,第二行是级别为 1 的星星的总数,如此类推,最后一行是级别为 N-1 的星星的总数
Sample Input
5
1 1
5 1
7 1
3 3
5 5
Sample Output
1
2
1
1
0
题解:看完题目,我们知道这题就是要求每个小星星不在它右边(x坐标可以相同)且在它下面的星星的数量。题目保证了数据的y坐标是升序的,所以只要求在某个数前面的数中x轴坐标不大于这个数的个数。就是求前缀和嘛。这里就要用到树状数组了(毕竟时间复杂度O(logn));由于y轴已经排好序,可以按照x坐标建立一维树状数组。(这里就不把数据离散化了,没什么大用)。
c++代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAXN=15010;//n最大为15010
const int MAXX=32010;//0<=x<=32010
using namespace std;
long long int n,c[MAXX],ans[MAXN];//ans数组为保存答案的数组,c数组为树状数组
long long int lowbit(long long int i)//求i用2的幂方和表示时的最小幂
{
return i&(-i);
}
void update(long long int i)//更新树状数组
{
while(i<=MAXX)//注意判断条件不是(i<=n)
{
c[i]+=1;
i+=lowbit(i);
}
}
long long int getsum(long long int i)//求前i个数的和(前缀和)
{
long long int h=0;
while(i>=1)
{
h+=c[i];
i-=lowbit(i);
}
return h;
}
int main()
{
memset(c,0,sizeof(c));
memset(ans,0,sizeof(ans));
cin>>n;
for(long long int i=1;i<=n;i++)
{
long long int x,y;
scanf("%lld%lld",&x,&y);
long long int s=getsum(x+1);//先求和,这里求和和更新都是用x+1,因为要考虑x=0的情况,全部加上1后对求前缀和没影响
update(x+1); //再更新
ans[s]++;//注意题目的输出描述,是要输出依次级别为i的数的个数
}
for(long long int i=0;i<n;i++)
cout<<ans[i]<<endl;//输出
return 0;
}