【树状数组】数星星(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; }