您的位置:首页 > 其它

POJ 2352 Stars 解题思路,树状数组

2015-04-28 09:12 393 查看
题目传送门    <a target=_blank href="http://poj.org/problem?id=2352">http://poj.org/problem?id=2352</a>
Stars


Time Limit: 1000MS Memory Limit: 65536K

Total Submissions: 35623 Accepted: 15462

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.

题目大意:有N个星星,给出N个星星的坐标,但是坐标给出的顺序有一定的规律,按照y坐标从小到大给出,当y坐标相同的时候按照x坐标的大小顺序给出;之后输出处在各个等级的星星的个数,等级就是看y坐标和x坐标同时小于等于这个星星的个数之和;

题目分析:由于N的数量是100000,想存下来这个图是完全不可能的,而且就算存下来,在做下面的运算是也会超时,所以我们要想到其他的办法来解决这个问题,其他基本上都不用树状数组了吧?那么我们就往加和上想呗!既然我们知道等级是按照y和x的优先级来输入的,并且y一定大于等于前面的星星的y!!那么算一个星星的等级的话我们只要判断有多少个星星是不是x是不是大于等于现在输入的x不就好了吗?(星星的等级,等级就是看y坐标和x坐标同时小于等于这个星星的个数之和) 大家好好想想是不是这样滴~~~~~~~~下面我们就切入正题吧:

下面贴出一种朴素的代码给大家来看看,加和的时候遍历,大家要先看懂这个代码才能继续往下看哦:

#include<cstdio>
#include<cstring>
int xx[32001],level[15001];
int main(void){
int n,i,sum,j,k,x,y;
while(scanf("%d",&n)!=EOF){
memset(xx,0,sizeof(xx));
memset(level,0,sizeof(level));
for(k=0;k<n;k++){
scanf("%d %d",&x,&y);
for(i=0,sum=0;i<=x;i++)
sum+=xx[i];
level[sum]++;
xx[x]++;
}
for(i=0;i<n;i++){
printf("%d\n",level[i]);
}
}
}


代码很简短,大家看看,应该都能明白我的意思,代码这么简洁,但是效果却是不好的。。。。超时了,我当时就想这么简单还超时,我晕!不过仔细想想这个代码的复杂度是O(x*n)的对吧?看看大小都10的9次方了。。。超时很正常。不过由于

由于这是学长出的树状数组的题目,我就往树状数组上面想怎么做喽,我就想树状数组唯一的好处就是加和,那么我们就在做加法的时候改成树状数组的加法的话不就是logN了吗?这样就是O(x*x)的算法啦,想想为什么是x*x而不是x*logN;

讲到树状数组就不得不提以下这几样东西

下面用tree[]来表示树状数组;对了,树状数组的下标必须要从1开始,否则建立不了!!!

第一:

lowbit-------简单意思就是数的大小用二进制表示的最后一位数是一的那个

写成代码的话就很简单了,

int lowbit(int x){
return x&-x;//其实我也不知道为什么这样写就可以这样来表示它的二进制,以后我再看看资料哈
}


第二:

树状数组如何进行储存


贴上代码:

void add(int i,int v){     //i表示现在输入的数要加上的位置,v表示的是这个位置要增加多大的值
for(;i<=MAX_N;i+=lowbit(i)){
tree[i]+=v;
}
}


第三:

树状数组如何做累加和

贴上代码:

int sum(int i){
int ans;
for(;i>0;i-=lowbit(i)){
ans+=tree[i];
}
return ans;
}


基本上就这么多了哈,树状数组的三个函数:

下面给出这一题的代码: 还没有看懂的就可以看看下面的代码怎么用这几个函数的,自己再好好理解一下哦

#include<cstdio>
#include<cstring>
#define MAX_N 32005
int tre[32005],level[15005];
int lowbit(int x){
return x&-x;
}
int sum(int i){
int ans=0;
for(;i>0;i-=lowbit(i)){
ans+=tre[i];
}
return ans;
}
void add(int i){
for(;i<=MAX_N;i+=lowbit(i)){
tre[i]+=1;
}
}
int main(void){
int n,i,a,b;
while(scanf("%d",&n)!=EOF){
memset(tre,0,sizeof(tre));
memset(level,0,sizeof(level));
for(i=0;i<n;i++){
scanf("%d %d",&a,&b);
a++;
level[sum(a)]++;
add(a);
}
for(int i=0; i<n; ++i)
printf("%d\n",level[i]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: