您的位置:首页 > 其它

ural(Timus) 1028 Stars

2013-03-15 13:59 344 查看
树状数组

经典入门题,只要搜索数星星就能在各个OJ找到这个题目,不过不同OJ的输入和输出可能不同,但是题意是一样的,就是统计每个星星的等级

入门题详细说一下。首先对输入的星星进行排序,先按x坐标升序排序,x坐标相同的按y坐标升序排序,这样做是后面能使用树状数组的根本保证。由于这题,输入数据中就已经保证了是按y坐标升序输入若y坐标相同则按x坐标升序输入,所以不需要排序,注意,两种排序方法是一样的。下面就按本题的来讲

树状数组中是由原数组变化得到的,a是原数组,c是树状数组,并且数组是从下标1开始的,为什么从1开始是因为位运算和二进制的一些问题。在这里我们已经知道0<=x,y<=32000,所以我们的数组长度就是这么大。为什么呢?因为我们统计的是x的个数

a[x]表示坐标为x的星星有多少个,所以c[x]就是对应的一段和c[x]=a[x-2^k+1]……a[x]。我们要知道一个星星的等级也就是其左下方有多少个星星,那么我们先知道在其左边有多少个星星,再知道其下面有多少个星星,但是其下面有多少个星星是不用计算的,已经知道了,为什么,因为数据是按照y升序排序的(现在终于知道了为什么要排序了)。那么也就说,对于第i个星星,前面i-1个星星一定在其下方或者同一水平线上(其后面的星星一定在其上方或者同一水平线上,是一定不符合要求的不用考虑)。只要在这些星星中选出一些星星,它们的x比第i个星星的x小,那么就可以计数了。我们初始化话原数组a和树状数组均为0,a[x]表示到目前为止,横坐标为x的星星有多少个,注意这个,到目前为止。所以没读入一个星星,就可以去更新a数组,即对应的a[x]加1,同样的a数组的变化要对应到c数组的变化。只要不断读入星星的坐标,并不断更新c数组就可以了。我们可以发现,a数组只是帮组我们理解,根本不需要用到它,所以是不需要专门开辟一个a数组的

由于一个星星的等级只和它前面的星星有关,和后面的星星无关,所以我们已经可以一边读入数据一边计算每个星星的等级了!排序保证了y坐标是递增的,我们只要知道横坐标为1到x的星星的个数就是当前星星的等级。

由于坐标中有0,但是树状数组是 从1开始的,所以对于每个x都要加1后再操作,否则是错误的

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 15010
#define MAX 32010

int c[MAX],ans
;

int lowbit(int n)
{ return n&(-n); }

int sum(int p)
{
int ans=0;
while(p)
{
ans += c[p];
p -= lowbit(p);
}
return ans;
}

void add(int p ,int n ,int k)
{
while(p<=n)
{
c[p] += k;
p += lowbit(p);
}
}

int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(c,0,sizeof(c));
memset(ans,0,sizeof(ans));

for(int i=0; i<n; i++)
{
int x,y,level;
scanf("%d%d",&x,&y);
level=sum(x+1);
//printf("level=%d\n",level);
ans[level]++;
add(x+1,MAX,1);
}

for(int i=0; i<n; i++)
printf("%d\n",ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: