算法知识-树状数组的实现思路

1、树状数组的构建

![](https://i-blog.csdnimg.cn/direct/b89919d2f8f0432cb9c8b6541a3ab446.png)
public static void main(String[] args) {
    int[] a = {0,1,2,3,4,5,6,7,8}; // a[0] 不起作用,数组从 1 开始

    int[] c = new int[a.length]; // 由于 a 数组从 1 开始,因此直接就是 a 的长度即可 
    for(int i = 1;i < c.length;i++) {
        for(int j = i-lowbit(i)+1;j <= i;j++) {
            c[i] += a[j];
        }
    }
}

2、树状数组的前缀和查询

![](https://i-blog.csdnimg.cn/img_convert/e9a69aa8a2c3a2c3940b6621f4b6b6be.png)
// 前 n 项的和
static int sum(int n) {
    int res = 0; // 这里 i 一定要 > 0 ,因为,0 - lowbit(0) = 0 无限循环
    for(int i = n;i > 0;i -= lowbit(i)) {
        res += c[i];
    }
    return res;
}

3、树状数组的更新操作

![](https://i-blog.csdnimg.cn/img_convert/88f35a14633910ff44e1ddfbd223e1ff.png)
static void update(int k,int x) {
    for(int i = k;i < c.length;i += lowbit(i)) {
        c[i] += x;
    }
}

4、树状数组的区间更新、区间查询

package 算法第二章_数据结构.树状数组;

/**
 * ClassName:区间修改_区间查询
 * Description:
 *
 * @Author:独酌
 * @Create:2025/4/9 21:19
 */
public class 区间修改_区间查询 {
    // 构造树状数组,注意:这里由于 a 数组的第 0 项没有用,因此可以直接与 a 数组的长度一致
    public static void main(String[] args) {
        int[] a = {0, 1, 2, 3, 4, 5, 6, 7, 8};
        int[] d = new int[a.length]; // 差分数组
        int[] da = new int[a.length]; // 差分数组的辅助数组
        // 因此:要求 a 的前 4 项的和就等于
        // 【d 的从 1 ~ 4 的前缀和 * 4 】- 【da 的从 1 ~ 4 的前缀和】

        int[] c1 = new int[a.length]; // 差分数组树状数组
        int[] c2 = new int[a.length]; // 差分数组的辅助数组的树状数组,因为,区间查询需要
        for (int i = 1; i < d.length; i++) {
            d[i] -= d[i + 1 == d.length ? 0 : i + 1] -= a[i];
            da[i] = (i-1) * d[i];
        }

        // 初始化,差分数组的树状数组
        for(int i = 1;i < d.length;i++) {
            update(i,d[i],c1);
        }

        // 初始化,辅助数组的前缀和
        for(int i = 1;i < da.length;i++) {
            update(i,da[i],c2);
        }

        // 求 [2 ~ 4] 的和
        System.out.println(sum(4,c1,c2) - sum(1,c1,c2));

        updatePlus(2,4,3,c1,c2);

        // 求 [2 ~ 4] 的和
        System.out.println(sum(4,c1,c2) - sum(1,c1,c2));
    }


    static int lowBit(int x){
        return x & (-x);
    }
    static int sum(int n,int[] c){
        int res = 0;
        for(int i = n;i > 0;i -= lowBit(i)) {
            res += c[i];
        }
        return res;
    }
    static void update(int i,int x,int[] c){
        for(int j = i;j < c.length;j += lowBit(j)) {
            c[j] += x;
        }
    }

    static int sum(int n,int[] c1,int[] c2){
        return n * sum(n,c1) - sum(n,c2);
    }

    static void updatePlus(int l,int r,int x,int[] c1,int[] c2){
        update(l,x,c1);  // 修改差分数组
        update(r+1,-x,c1);

        update(l,x * (l-1),c2); // 修改辅助数组,因为d[i]变了(这里由于 da[i] = (i-1)d[i],因此,
                                   // 结果应该是:(i-1)*(d[i]+k),因此加上:(i-1) * k)
        update(r+1,-x * r,c2);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值