POJ2352_stars_solution

来源:互联网 发布:java中的properties类 编辑:程序博客网 时间:2024/06/07 22:15
Stars
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 27201 Accepted: 11912

Description

Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given star. Astronomers want to know the distribution of the levels of the stars.

For example, look at the map shown on the figure above. Level of the star number 5 is equal to 3 (it's formed by three stars with a numbers 1, 2 and 4). And the levels of the stars numbered by 2 and 4 are 1. At this map there are only one star of the level 0, two stars of the level 1, one star of the level 2, and one star of the level 3.

You are to write a program that will count the amounts of the stars of each level on a given map.

Input

The first line of the input file contains a number of stars N (1<=N<=15000). The following N lines describe coordinates of stars (two integers X and Y per line separated by a space, 0<=X,Y<=32000). There can be only one star at one point of the plane. Stars are listed in ascending order of Y coordinate. Stars with equal Y coordinates are listed in ascending order of X coordinate.

Output

The output should contain N lines, one number per line. The first line contains amount of stars of the level 0, the second does amount of stars of the level 1 and so on, the last line contains amount of stars of the level N-1.

Sample Input

51 15 17 13 35 5

Sample Output

12110

Hint

This problem has huge input data,use scanf() instead of cin to read data to avoid time limit exceed.

Source

Ural Collegiate Programming Contest 1999
题目的意思就是,对于在(x_cur,y_cur)的星星,去求那些x<=x_cur&&y<=y_cur的星星数量,任意两个星星的坐标不会重合。
这个题目已经告诉你,输入的时候是按y坐标递增输入的,实际上就是省了自己排序了,如果不这样输入,那自己排一下序也是一样的。接下来要做的就是对于当前输入的x_cur,查询前面的所有x中有几个比x_cur要小的元素,有几个就是level几了,第一个肯定是level 0了。如果使用蛮力法,N的数量级很大,蛮力需要O(N^2)才能搞定,显然是不行了。仔细看x,y有个限制条件,就是都<=32000,为什么会出现这个信息呢,实际上也是提醒我们需要从坐标来入手。这个题目的标准解法是树状数组,实际上(x,y)这个限制条件可以更宽松,比如10^6也是可以的,但一定要加以限制,否则要超内存。
我们转换一下思维,对于当前输入的x_cur,对于后面所有出现的比x>=x_cur的数,它的level级别都会+1。我们假设后面不知道会出现什么x,我们姑且用个lev[]数组hash一下,把所有x>=x_cur的位置都+1,那么对于后面出现的x,只要查看一下lev[x]就可以知道自己的level级别了。现在就是怎么更新lev[]的问题了。
再转化一下,可以认为lev[i]保存的就是一个数组[1,i]这个区间的和,这个数组的长度为32000,它的每个元素为0,当某个元素更新时,它只有加1一种操作,第i(相当于x)个位置更新时,显然[i,32000]这些位置的和都要加1。其实这就已经完全转化为树状数组了。下面给出代码,有疑问的初学者可以仔细思考一下,再去把树状数组模拟几遍。
#include<stdio.h>#include<string.h>int treeArray[32005],lev[15005],n,sum;//treeArray就是树状数组,lev是记录每个等级的数量int a,b,i;int lowbit(int x)//获得x的最低位{return x&(-x);}void update(int pos,int value)//将pos+1,那么>=pos的和都要加1{while(pos<=32001)//这个一定要注意pos为0的情况,因为x坐标可能为0,不如将每个坐标都加1,避免死循环{treeArray[pos]+=value;pos+=lowbit(pos);}}int getsum(int pos)//返回[1,pos]的和,即前面出现了多少次<=x的情况{sum=0;while(pos){sum+=treeArray[pos];pos-=lowbit(pos);}return sum;}int main(){while(scanf("%d",&n)!=EOF){memset(lev,0,sizeof(lev));memset(treeArray,0,sizeof(treeArray));for(i=1;i<=n;i++){scanf("%d%d",&a,&b);lev[getsum(a+1)]++;//getsum()得到等级,lev保存相应等级的数量update(a+1,1);//先查询,在更新}for(i=0;i<n;i++)printf("%d\n",lev[i]);}return 0;}/*51 15 17 13 35 5*/

原创粉丝点击