树状数组

树状数组

一维树状数组

       假设c[] 为树状数组,a[]为原数组,它们的关系是,c[i]代表从a[i]开始往前2^k个元素的和。(k为i转化成二进制后尾部包含0的个数)。数组的下标从1开始。


即 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[7];

   c[8] = a[1] +a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8];

       数据间的相互关系构成了一颗树。每一个数都用二进制表示。


       通过位运算求2^k = i&(-i)。一系列的操作都是在O(1),因为一个数的二进制位数是一定的。比如 (x += x &(-x))&& x < N,每循环一下,x的最低二进制高向至少上移了一位 8 -> 16 ->32,从上图的树状数组的结构图也可以看出。

int c[N];
int lowbit(int k)
{
    return k&(-k);
}
void modify(int x,int value)
{
    for (int i =x; i < N; i += lowbit(i))
        c[i] +=value;
}
int sum(int x)
{
    int s = 0;
    for (int i =x; i >= 1; i -= lowbit(i))
        s += c[i];
    return s;
}

       树状数组可以快速的统计出一段连续区间的值,线段树也可以做到,一般树状数组会稍快一些。i处的值为 sum(i)– sum(i-1)。


       按照这个原理,可以很方便的推广到二维树状数组。

二维树状数组

   二维树状数组的思想几乎一样,也可以推广到三维、四维。

int dp[N][N];
int n,m;
int LowBit(int k)
{
    return k& (-k);
}
void modify(int x,int y,int value)
{
    for (int i =x; i <= n; i += LowBit(i))
        for (intj = y; j <= m; j += LowBit(j))
           dp[i][j] += value;
}
int sum(int x,int y)
{
    int s = 0;
    for (int i =x; i >= 1; i -= LowBit(i))
        for (intj = y; j >= 1; j -= LowBit(j))
            s +=dp[i][j];
    return s;
}

    二维树状数组在i,j处的值为sum(i,j)+sum(i-1,j-1)-sum(i-1,j)-sun(i,j-1).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值