首页 > 其他分享 >树状数组

树状数组

时间:2024-11-29 22:55:36浏览次数:4  
标签:index 前缀 树状 int res 数组

前缀和之树状数组

树状数组(Fenwick Tree)是一种用于高效处理区间查询与修改的重要工具。它可以在 (O(log n)) 的时间复杂度内完成单点更新和前缀区间求和的操作。

一、树状数组的基本思想

树状数组通过一个辅助数组 (c[i]) 实现,将原数组的信息以一种特殊的方式存储,使得查询和更新都能快速完成。其核心思想是利用数组的二进制表示,按区间段存储部分和。

例如,假设数组下标从 (1) 开始:

  • (c[i]) 保存的是从 (i) 减去 (lowbit(i)) 再加 (1) 到 (i) 的区间和。这里的 (lowbit(i)) 表示 (i) 的二进制表示中最低位的 (1) 所对应的值,其计算方式是 (lowbit(x)=x) 与 (-x) 的按位与运算结果(即 (lowbit(x)=x & (-x)))。
    image

二、树状数组的结构特点

通过树状数组,我们可以快速实现以下两个操作:

(一)单点更新

更新数组中的某个值,同时维护相关区间和。

(二)区间查询

计算从起点到某点的前缀和。

1. 示例:计算前缀和

以数组 (a[1..n]) 为例,假设使用树状数组存储信息,我们可以用如下伪代码完成前缀和计算:

// 查询从索引1到指定index的前缀和
    public int query(int index) {
        int res = 0;
        while (index > 0) {
            res += tree[index];
            index -= index & -index;
        }
        return res;
    }

2. 示例:单点更新

当我们想更新 (a[k]) 的值(例如加上 (y)),树状数组中的相关节点也需要同步更新。具体实现如下:

// 对指定索引index处的元素进行单点更新,增加val的值
    public void add(int index, int val) {
        while (index <= n) {
            tree[index] += val;
            index += index & -index;
        }
    }

三、树状数组的实际应用

树状数组具有广泛的实际应用,特别是在需要频繁查询和更新的场景中:

(一)区间求和问题

计算任意子区间的和。

(二)动态排序统计

例如,求解逆序对数。

(三)二维平面问题

如处理棋盘上的子矩阵求和。

代码实现

以下是树状数组的基本实现代码:

public class BinaryIndexedTree {
    // 表示树状数组所处理的序列长度
    private int n;
    // 树状数组本身
    private int[] tree;

    // 构造函数,用于初始化树状数组,这里假设传入的数组长度就是要处理的长度n
    public BinaryIndexedTree(int[] arr) {
        n = arr.length;
        tree = new int[n + 1];
        // 初始化树状数组,可根据具体需求调整初始化逻辑
        for (int i = 0; i < n; i++) {
            add(i + 1, arr[i]);
        }
    }

    // 查询从索引1到指定index的前缀和
    public int query(int index) {
        int res = 0;
        while (index > 0) {
            res += tree[index];
            index -= index & -index;
        }
        return res;
    }

    // 对指定索引index处的元素进行单点更新,增加val的值
    public void add(int index, int val) {
        while (index <= n) {
            tree[index] += val;
            index += index & -index;
        }
    }

    // 示例用法展示
    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9};
        BinaryIndexedTree bit = new BinaryIndexedTree(arr);

        // 查询索引为3的前缀和
        int prefixSum = bit.query(3);
        System.out.println("索引为3的前缀和: " + prefixSum);

        // 对索引为2的元素进行单点更新,增加2
        bit.add(2, 2);

        // 再次查询索引为3的前缀和
        prefixSum = bit.query(2);
        System.out.println("更新后索引为2的前缀和: " + prefixSum);
    }
}

标签:index,前缀,树状,int,res,数组
From: https://www.cnblogs.com/clarencezzh/p/18577757

相关文章

  • 【每日一题】209. 长度最小的子数组
    给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl,numsl+1,...,numsr-1,numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。示例1:输入:target=7,nums=[2,3,1,2,4,3]......
  • 力扣每日一题 单调数组对的数目(dp)
     题目困难 动态规划给你一个长度为 n 的 正 整数数组 nums 。如果两个 非负 整数数组 (arr1,arr2) 满足以下条件,我们称它们是 单调 数组对:两个数组的长度都是 n 。arr1 是单调 非递减 的,换句话说 arr1[0]<=arr1[1]<=...<=arr1[n-1] 。arr2......
  • 【每日一题】3251. 单调数组对的数目 II
      给你一个长度为 n 的 正 整数数组 nums 。如果两个 非负 整数数组 (arr1,arr2) 满足以下条件,我们称它们是 单调 数组对:两个数组的长度都是 n 。arr1 是单调 非递减 的,换句话说 arr1[0]<=arr1[1]<=...<=arr1[n-1] 。arr2 是单调 非递增 ......
  • C语言 - 指针,数组
    指针指针入门创建变量intage=10;创建指针,指向变量指针类型*指针变量=&变量int*p=&age;当有了指针之后,就可以通过指针操作他指向的数据了通过指针获取指向的位置的数据,在指针前面加一个*为解引用指针前加*修改,改的是指针指向的位置的值指针的作用:游......
  • SZU实验八数组2【id:362】【15分】D. 矩阵操作(数组)
    题目描述给定一个N阶初始矩阵,现有以下操作TRANSLATE:转置,即将aij变为aji,操作结束后输出矩阵,并将这一新矩阵储存至原二维数组中。ADD:将该矩阵与一矩阵相加得到一新矩阵,操作结束后输出这一新矩阵,并将这一新矩阵储存至原二维数组中。MULTIPLY:与该矩阵与一矩阵相乘得到一......
  • 搜索旋转排序数组习题分析
    习题:(leetcode33)整数数组 nums 按升序排列,数组中的值 互不相同 。在传递给函数之前,nums 在预先未知的某个下标 k(0<=k<nums.length)上进行了 旋转,使数组变为 [nums[k],nums[k+1],...,nums[n-1],nums[0],nums[1],...,nums[k-1]](下标 从0开始 计数)。例如, ......
  • 算法:数组 #241125
    算法:数组理论二分查找移除元素二分查找题目链接:leetcode#704给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1。题目的前置条件为n个有序的元素,故可通过二分查找解题找到中......
  • 查找数组中相似字段(数组里面某个值相似归类到一起)
    例如↓数组中每条数据的url字段相似arr=[{id:0,dir:'/edit/aaaa/bbbb/cccc/dddd/20231123',title:'第一条数据'},{id:1,dir:'/edit/aaaa/bbbb/cccc/dddd/20241011',title:'第二条数据'},......
  • 力扣刷题——3251. 单调数组对的数目 II
    考虑arr1可以取到的数字组合数,从0到i+1位置的合法的arr1组合数,可以从0到i的组合数得到。因此可以想到用动态规划解决问题,使用一个数组dp[i][j]代表arr1[i]=j时,前i+1个数字有多少个组合。这样一来,最终的答案即为sum(dp[n-1][0...M],其中M为nums中最大值。根据这个思路写出一个简......
  • php 对空数组元素??并进行运算,可能触发 Undefined index 错误
    对空数组元素??并进行运算,可能触发Undefinedindex错误$TotalGb=$TotalGroupBrand[$brandNameEn]??[];$quantity=$TotalGb['stock']??0+$TotalGb['unshipped_qty']??0;"#报错:Undefinedindex:unshipped_qty",代码中的错误"Undefinedindex:......