您的位置:首页 > 其它

hdu 1166 敌兵布阵(我的第一道树形数组)

2013-07-16 22:43 239 查看
树形数组,一直久闻其名。经常有人拿他和线段树做比较。就这道题来说,效率确实比线段树高了不少。

对于一个数组来说,如果我们想多次求它的一个区间的和的话,最好的方法是将a[i]中存入这个数组的前i项和。当我们想要求区间[x,y]内所有数据的和的话,我们只需要用a[y]减去a[x-1]就行了。但是这个方法的问题是,如果我们修改了其中第k项的值的话,那么我们就必须修改后面所有数据的值。

在线段树中,这种区间求和的问题很好处理,简直就是线段树最擅长处理的问题之一了。线段树对于任何一个值的修改效率是logn,而在修改完返回根节点的时候,顺路就更新了所有与这个节点相关区间的值。

树形数组则是用了另一种原理,a[i]存得值得数量是lowBit[i],lowBit是代码中的函数。这个方法优秀的地方是这个数值可以通过某种方式传递,类似于线段树中子节点的在返回根节点的过程中顺路修改一样,在树形数组中这样的修改效率是可以在logn的时间内完成的,在查询区间的值上,树形数组也有着不俗的效率,而且非常节约空间。

非常尴尬的是我似乎解释不了lowBit函数的原理。。。。

#include<stdio.h>
#include<string.h>
#define N 50005
int a
,b
;
int n;
int lowBit(int x)
{
return x&(-x);
}
int Sum(int x)
{
int sum=0;
while(x)
{
sum+=a[x];
x-=lowBit(x);
}
return sum;
}
int Find(int x,int y)
{
return Sum(y)-Sum(x-1);
}
void Update(int x,int y)
{
while(x<=n)
{
a[x]+=y;
x+=lowBit(x);
}
return ;
}
int main()
{
int T;
scanf("%d",&T);
int cnt=1;
while(T--)
{
scanf("%d",&n);
int i;
char s[10];
memset(a,0,sizeof(a));
for(i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
Update(i,x);
}
getchar();
int flag=1;
while(1)
{
int x,y;
scanf("%s",s);
if(s[0]=='E')
break;
scanf("%d%d",&x,&y);
if(s[0]=='A')
Update(x,y);
else if(s[0]=='S')
Update(x,-y);
else
{
if(flag)
{
printf("Case %d:\n",cnt++);
flag=0;
}
printf("%d\n",Find(x,y));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: