码迷,mamicode.com
首页 > 编程语言 > 详细

树状数组

时间:2015-03-29 00:27:44      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:

  

  树状数组主要用于快速的更改某个点的值和查询某个区间的和,是一种比较小巧的数据结构.先看下图:

      技术分享

  假设数组A[]是我们要操作的对象,则数组C[]则是数组A[]相对应的树状数组.观察上图,我们得到数组C[]前八个值:

  C[1]=A[1]

  C[2]=A[1]+A[2]

  C[3]=A[3]

  C[4]=A[1]+A[2]+A[3]+A[4]

  C[5]=A[5]

  C[6]=A[5]+A[6]

  C[7]=A[1]

  C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8]

.......

  可以总结一个规律:当 i 为奇数时: C[i]=A[i];当 i 为偶数时: C[i]=A[i-2^k+1]+..A[i](k表示 i 最多有2的k次幂).

  例如: 6的因子中有2的一次幂,等于2,所以C[6]=A[5]+A[6](由六向前数两个数的和),4的因子中有2的两次幂,等于4,所以C[4]=A[1]+A[2]+A[3]+A[4](由四向前数四个数的和).

  对于任一个数组对应的树状数组有公式: C[n]=A[n-2^k+1]+....+A[n](其中k为n的二进制表示中从右往左数的0的个数)

  对于求2^k有如下代码:

int lowbit(int x)
{
    return x & (-x);
}

  

  

  求区间和操作

  假设我们要求区间[1,7]的和,用sum(7)表示,观察上图可知: sum(7)=C[7]+C[6]+C[4].
具体代码如下:

// 求区间[1,i]的和
int sum(int i)
{
    int s=0;
    while(i>0)
    {
        s += c[i];
        i -= lowbit(i);
    }
    return s;
}

 

  更新某个点的值

  当数组需要变更的时候,树状数组就发挥了它的优势,假设我们要给某个节点 i 的值加上 x.

算法包含两步:

  ① 当 i<=n 时,执行下一步;否则的话,算法结束;

  ② c[i] += x; i+=lowbit(i).

例如,在上面的示意图中,假设更改的元素是a[2],那么它影响到得c数组中的元素有c[2],c[4],c[8],我们只需一层一层往上修改就可以了,这个过程的最坏的复杂度也不过O(logN);

具体代码如下:

 

// 把节点 i 的值加上 x.
void Update(int i, int x)
{
    while(i<=n)
    {
        c[i] += x;
        i += lowbit(i);
    }
}

 

 

技术分享
int lowbit(int x)
{
    return x&(-x);
}

void update(int x, int y, int val) //将 a[x][y] 的值增加val
{
    for(int i=x; i<N; i+=lowbit(i))
    {
        for(int j=y; j<N; j+=lowbit(j))
        {
            sum[i][j] += val;
        }
    }
}


int getSum(int x, int y) //求以1,1为左上角端点,学校,x,y为右下角端点的矩阵和.
{
    int s = 0;
    for(int i=x; i>0; i-=lowbit(i))
    {
        for(int j=y; j>0; j-=lowbit(j))
        {
            s += sum[i][j];
        }
    }
    return s;
}
View Code

 

树状数组

标签:

原文地址:http://www.cnblogs.com/khan724/p/4375043.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!