简单树状数组-poj2352

16 篇文章 0 订阅

【树状数组】数星星(POJ2352 star

Time Limit:1000MS  Memory Limit:65536K
Total Submit:23 Accepted:16

题目:http://poj.org/problem?id=2352

Description

天文学家经常观察星象图。星象图中用平面上的点来表示一颗星星,每一颗星星都有一个笛卡尔坐标。设定星星的等级为其左下角星星的总数。天文学家们想知道星星等级的分布情况。


比如上图,5号星星的等级为3(其左下角有编号为1、2、4的星星共三颗)。2号星星和4号星星的等级为1。在上图中只有一颗星星等级为0,两颗星星等级为1,一颗星星等级为2,一颗星星等级为3。
给定一个星象图,请你写一个程序计算各个等级的星星数目。

Input

输入的第一行包含星星的总数N (1<=N<=15000)。接下来N行,描述星星的坐标(X,Y)(X和Y用空格分开,0<=X,Y<=32000)。星象图中的每个点处最多只有一颗星星。所有星星按Y坐标升序排列。Y坐标相等的星星按X坐标升序排列。

Output

输出包含N行,每行一个整数。第一行包含等级0的星星数目,第二行包含等级1的星星数目,依此类推,最后一行包含等级为N-1的星星数目。

Sample Input

5

1 1

5 1

7 1

3 3

5 5

Sample Output

1

2

1

1

0

 首先我们要理解树状数组是干什么的。。。

树状数组(参考百度百科)

 

         树状数组是一个查询和修改复杂度都为log(n)的数据结构,假设数组a[1..n],那么查询a[1]+...+a[n]的时间是log级别的,而且是一个在线的数据结构,支持随时修改某个元素的值,复杂度也为log级别。

         设树状数组为sum,则sum[k]为k管辖区间的元素的和,这个区间为2^t(其中t为k二进制末尾0的个数),sum[k]= Cn = A[k – 2^t+ 1] + ... + A[k]。这个数据结构包括计算1~k的和、a[k]更新后的调整两个操作。具体参考代码。

例子:

 

A为被计数数组,C为树状数组(计数)

0000 0001:C1 = A1
0000 0010:C2 = A1 + A2
0000 0011:C3 = A3
0000 0100:C4 = A1 + A2 + A3 + A4
0000 0101:C5 = A5
0000 0110:C6 = A5 + A6
0000 0111:C7 = A7
0000 1000:C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
...
0001 0000:C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15+ A16

这个应该很好理解,下面我们来看树状数组的三大法宝。。。。有了他们,树状数组的大部分问题都会迎刃而解。。。。

  求最小幂2^k:

int lowbit(int k)
{
	return k&(-k);//求2^k 
}
   对某个元素进行加法操作

int add(int i,int v)
{//如果要把a[i]增加v,可以通过调用如下函数实现
	while(i<=N)
	{
		sum[i]+=v;
		i+=lowbit(i);
	}
	return 0;
}
求前n项和:
int getsum(int i)//如果要统计a[1]到a[i]之间的和,可以通过调用如下函数实现
{
	int s=0;
	while(i>0)
	{
		s+=sum[i];
		i-=lowbit(i);
	}
	return s;
}

下面看看本题的代码:

#include<stdio.h>
#include<string.h>
#define N 32005
int sum[N];
int lowbit(int k)
{
	return k&(-k);//求2^k 
}
int add(int i,int v)
{//如果要把a[i]增加v,可以通过调用如下函数实现
	while(i<=N)
	{
		sum[i]+=v;
		i+=lowbit(i);
	}
	return 0;
}
int getsum(int i)//如果要统计a[1]到a[i]之间的和,可以通过调用如下函数实现
{
	int s=0;
	while(i>0)
	{
		s+=sum[i];
		i-=lowbit(i);
	}
	return s;
}
int main()
{
	int n,i,x,y;
	int result[32005];
	memset(sum,0,sizeof(sum));
	memset(result,0,sizeof(sum));
	while(scanf("%d",&n)!=EOF)
	{
	
	for(i=0;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		result[getsum(x+1)]++;//统计 
		add((x+1),1);//
	}
	for(i=0;i<n;i++)
	 printf("%d\n",result[i]);
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值