当前位置:   article > 正文

数据结构----树状数组----子区间的和_树状数组 子区间和

树状数组 子区间和

一、几个问题

问题一:已知数组a[],元素个数为n,现在要求a数组中i到j区间内的和(1<=i<=j<=n)

解法1:每次查询就把i到j之间每个元素都加起来。最坏情况O(Qn)(Q为查询次数)

解法2:用前缀和数组sum[k]来记录1到k的和,查询时,就输出sum[j]-sum[i-1]。O(1)

问题二:已知数组a[],元素个数为n,现在有两种操作

1、求a数组中i到j区间内的和(1<=i<=j<=n)

2、将a数组中a[k](1<=k<=n)的值加上d。

解法1:每次查询就把i到j之间每个元素都加起来,每次更改就把a[k]加上d。最坏情况O(Qn)

解法2:用前缀和数组sum[k]来记录1到k的和,查询时,就输出sum[j]-sum[i-1],更改时,就把k到n之间的所有元素都加上d。最坏情况O(Qn)

解法3:树状数组。O(Qlog(n))

树状数组就是在这种背景下产生的。

二、树状数组的概念

利用二进制来分类,每一个数存的数据是存的一个区间,它存的区间大小,取决于它的二进制里权值最低的1权值,

如果感觉听不懂,就来看一下例子吧。

比如说6,转化成二进制位110,权值最低的1就是红色标注的那个1,它的权值是2。

比如说12,转化成二进制位1100,权值最低的权值就是4。

求它的最低权值有一个简便算法:

int lowbit(int x)

{

return x&-x;
}


接下来就是求和的操作,我们发现1~14之间的和是a[14]+a[12]+a[8],恰好是14对应二进制a[1110],a[1100],a[1000]

(以上的1110、1100、1000位二进制),于是可以发现求和算法:

int getsum(int x)

{

int sum=0;

while(x){

sum+=treearray[x];

x-=lowbit(x);
}
}

然后是修改操作,实际上就是找它的父亲,直到它的父亲大于n为止。

void update(int x,int d)

{

while(x<=n){

treearray[x]+=d;

x+=lowbit(x);
}
}

有了这三个函数,求解上面的问题就容易多了,但是要注意初始化:
for(i=1;i<=n;i++){

scanf("%d",&x);

update(i,x);
}


完整代码:

  1. #include<cstdio>
  2. int treearray[1000002],N;
  3. int lowbit(int x)
  4. {
  5. return x&-x;
  6. }
  7. int getsum(int x)
  8. {
  9. int sum=0;
  10. while(x){
  11. sum+=treearray[x];
  12. x-=lowbit(x);
  13. }
  14. return sum;
  15. }
  16. void update(int i,int x)
  17. {
  18. while(i<=N){
  19. treearray[i]+=x;
  20. i+=lowbit(i);
  21. }
  22. }
  23. int main()
  24. {
  25. int Q,i,a,b,x;
  26. scanf("%d%d",&N,&Q);
  27. for(i=1;i<=Q;i++){
  28. scanf("%d%d%d",&x,&a,&b);
  29. if(x==0){
  30. update(a,b);
  31. }
  32. if(x==1){
  33. printf("%d\n",getsum(b)-getsum(a-1));
  34. }
  35. }
  36. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/711462
推荐阅读
相关标签
  

闽ICP备14008679号