POJ 2352 Star (树状数组)

来源:互联网 发布:2017淘宝双11活动规则 编辑:程序博客网 时间:2024/05/29 11:31
Stars
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 41338 Accepted: 18004

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.


题目很好理解,求每个星星的等级,我们可以一个一个按照顺序加星星,每加一次都对这个星星求前缀和,这个就是这个星星的等级,直接暴力求是要超时的,因为数据要在线增加,所以这里要用到树状数组来维护。

首先先来说一个lowbit(x),这个子函数的用处是来求x的二进制最低位的1及其后面的0所代表的数,比如38288 的二进制是 1001010110010000,那么lowbit(38288)=10000(二进制)=16(十进制),给出lowbit的求法:lowbit(x)=x&-x;

然后我们把一个数组中的下标用lowbit处理之后分成,形成类似于一棵树的状态:

                                   
其中的a数组为基础数组,而c数组这是我们要维护的数组,而c数组是怎么维护的,我们先来看一个结论:对于一个节点i,如果他是左子树,那么他的父节点就是i+lowbit(i),如果他的右子树,那么他的父节点就是i-lowbit(i
).

然后我们再来维护c数组,c数组中的每个元素都是A数组中一段连续和,c[i]是以a[i]为终点的连续和,那么起点在哪里,我们就要用到上面的那个结论,cn表示的求以an为终点向左求lowbit(n)个数的连续和,也就是以该点为右节点,求从这个点的父节点+1开始到他本身的a元素的连续和,我们从左往右建立c数组。然后我们来求前缀和,用sum函数来求得:

int sum(int x){    int ret=0;    while(x>0)    {        ret+=c[x];        x-=lowbit(x);    }    return ret;}
如果我们修改a数组中的某个值,我们就需要更新c数组,更新函数如下:

void add(int x,int d) //x为坐标,d为修改的值的增减数{    while(x<=n)    {        c[x]+=d;        x+=lowbit(x);    }}

两个操作的时间复杂度都是logn,先对a数组进行预处理求出c数组,然后根据需要求和,在预处理中,我们进行n次add操作来建立树状数组既可。

最后附上本题的AC代码。(本题有一个坑点就是x可能等于0,在处理过程中应将x坐标后移一位保证以下标1开始)

#include<string.h>#include<algorithm>#include<stdio.h>using namespace std;int ans[40000];int c[40000];int n;int maxx,minx;inline int lowbit(int x){    return x&-x;}int sum(int x){    int ret=0;    while(x>0)    {        ret+=c[x];        x-=lowbit(x);    }    return ret;}void add(int x,int d){    while(x<=33000)    {        c[x]+=d;        x+=lowbit(x);    }}int main(){    while(scanf("%d",&n)!=EOF)    {    memset(c,0,sizeof(c));    memset(ans,0,sizeof(ans));    int tempans;    int tempx,tempy;    for(int i=1;i<=n;i++)    {        scanf("%d%d",&tempx,&tempy);        tempx++;        add(tempx,1);        tempans=sum(tempx);        ans[tempans]++;    }    for(int i=1;i<=n;i++)        printf("%d\n",ans[i]);    }return 0;}




0 0