1999年乌拉尔大学编程竞赛 星星

即使知道了是用树状数组解,这道题还是比较的有挑战的。


 

思路:

开始时,我的思路就掉坑里了。我想的是用类似二维前缀和的思想,记录每个矩形右上角的点的坐标(如(1,9)),将矩形转换成区间(1到9)来解。但显然,这个思路行不通,因为我找不到如何用树状数组来处理这些区间。(但我觉得这个思路会有用,将它记录在这)

进入正题。题目已经说明了,坐标会按照从低到高,从左到右的顺序给出。那么对于任意一颗星星,当它被处理时,其余的星星一定都不会高于它的高度,也就是说,其余的星星永远都满足高度不高于当前星星这一条件。那么此时,一个星星只要再满足x坐标不大于当前星星,这颗星星就可以为当前星星的等级作贡献。

这样去掉了高度一维,问题就变得简单了。维护一个树状数组,记录1~i这一区间内有多少颗星星(前面我们已经说明过,不用考虑星星的高度,因为能被记录下来的星星,高度必然不高于当前星星),每次读入一颗星星,查找1~当前星星x坐标的区间内有多少颗星星,即为当前星星的等级,桶排记录下来就行了。


 

代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=32002;//刚开始N只开到了32001,结果x加1后越界了,呜呜~~ 
int n,x,y,tr[N],ans[N];
void update(int x)
{
	for(;x<N;x+=x&(-x))
	tr[x]++;
}
int sum(int x)
{
	int s=0;
	for(;x;x-=x&(-x))
	s+=tr[x];
	return s;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		ans[sum(x+1)]++;//等级为sum(x+1)的星星个数加1 
		update(x+1);//x会出现0,而树状数组只能维护1~n的区间,所以要加1
	}
	for(int i=0;i<n;i++)
	printf("%d\n",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45383207/article/details/112387472