树状数组

力扣307

场景:一个数组 有两个操作 

1. 修改某个元素数值

2.求前n个数/区间数值和

如果我们对数组元素两两求和,如图

然而 图中没用的数字 有很多

可以发现 每一层的第偶数个数字都是没用的(在计算和时 直接用它正上方的数字就好)

如计算前5个数字和时,只需要把前四个数字和19加上第五个数字5即可

观察发现剩下的数据正好有n个,我们可以把这些数据装进一个数组中,这个数组正好和原数组一样长,也就是树状数组。

每一个元素都对应着一段区间和 求和时 我们只需要找到对应的区间即可。

修改数据时也只需要修改包含该数据的几个区间即可。

题目代码如下:

class NumArray {
    int[] tree;
    int lowbit(int x) {
        return x & -x;
    }
    int query(int x) {
        int ans = 0;
        for (int i = x; i > 0; i -= lowbit(i)) {
            ans += tree[i];
        }
        return ans;
    }
    void add(int x, int u) {
        for (int i = x; i <= n; i += lowbit(i)) {
            tree[i] += u;
        }
    }

    int[] nums;
    int n;
    public NumArray(int[] _nums) {
        nums = _nums;
        n = nums.length;
        tree = new int[n + 1];
        for (int i = 0; i < n; i++) {
            add(i + 1, nums[i]);
        }
    }

    public void update(int i, int val) {
        add(i + 1, val - nums[i]);
        nums[i] = val;
    }

    public int sumRange(int l, int r) {
        return query(r + 1) - query(l);
    }
}

lowbit函数 x&(-x)的结果是:

1.x为奇数 结果为1

2.x为偶数 结果为能整除这个偶数的最大的2的幂, 即: m = x & -x , 则 x % m = 0, 且 m = 2^k

性质:

1.对于b[i]来说,它所对应的区间长度为 lowbit(i)

2.计算前i个元素的和sum(i)时,sum(i)=sum(i - lowbit(i)) + b[i] (性质1可得b[i]所代表的区间长度为lowbit(i))

3.一个序列正上方的序列正好是b[i + lowbit(i)],所以我们在修改某个值的时候 只需要不断向上加lowbit(i)就可以了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值