• 树状数组学习笔记


    参考自:http://www.cnblogs.com/huangxincheng/archive/2012/12/05/2802858.html

    0. 介绍(来自wikipedia)

      - 树状数组, 又称二分索引树(Binary Indexed Tree, BIT), 用于高效计算数列的前缀和.

      - 它可以以O(log n)的时间得到sum_{i=1}^N a[i],并同样以O(log n)对某项加一个常数。

    1. 数据结构定义

      - 存放原始数据元素的数组a (i.e.  int[]  a)

      - 树状数组 s   (i.e.   int[] s)

      - 注意:

        - 原始数据数组 a 可能是隐含的, 因为 s[i] 中包含a[i], 而且也可以通过 s[i]-s[i-1] 来计算得到 a[i].

        - 树状数组s只是一个维护 a 信息的数据结构, 可能本身不对应实际的物理含义, 是一种抽象的结构.

    2. 说明:

      - s 和 a 的大小一样大

      - 当a全为0 的时候, s也全为0.

      - s 的build 是基于维护a的, 但是a不一定是现成的, 有时候可能通过从0开始动态构建(参考题解poj 2352).

      - 下标从 1 开始计算, 因为后面要用到二进制格式末尾 连续0 的个数. 所以如果用 0 的话不太好处理.

    3. 公式(2个等效的, 公式1用于理解, 计算主要用公式2)

      - 1. s[i]=a[i-2k+1]+a[i-2k+1+1]+......+a[i-1]+a[i]   (if i-2k+1 < i )   

        - 2. s[i]=a[i] + s[j]   (j= i-1 decreasing to i-2k+1 , j -= 2t, t=lowbit(j) )

         - s[i] 表示 树状数组第i个元素,  并不是前 i 个元素的和.

        - k 表示 i 的二进制格式的末尾连续0的位数( i.e.    i=610=110  => k = 1) , 也代表s[i] 在树状结构中的层数 (i.e.  s[6] 在 level 1,  from level 0).

        - 2表示 s[i] 中包含原始数据 数组 a 中的元素个数  如s[6] = a[5] + a[6], 因为 k=1,  2k为2, 利用公式计算得到 a[5] 和 a[6].  a[i-2k+1] 算出 a[5]为起始项.

    4. 工具代码

      - 求 2 值

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

      - 建立树状数组

        - 注意: 只有当原始数据数组准备好之后才能用这个方法. 如果没有, 应该使用动态构建(先初始化s, 然后根据条件构建s到完整的树状数组).

    //根据原始数据数组建立树状数组 s
    void build(){
        for (int i=1;i<=MAX_N;i++){ // s(i) 为计算的目标值
            s[i]=a[i]; // 基础值, s(i)必定包含 a(i)
            // 根据公式2, 倒着加回去, 从s(i-1) 加回去到 i-2k+1. 
            for (int j=i-1; j>=i-lowbit(i)+1;j-=lowbit(j)) //j每次减去的是j二进制中的每一位, 所以这个循环复杂度是O(logn)
                s[i]+=s[j];
        }
    }

      - 查询: 求前n项和, 继而也可以求任意区间之和. (logN)

    //计算前n项和
    int sumn (int n){
        int sum = 0;
        //利用公式进行计算.
        for (int i = n; i > 0; i -= lowbit(i)) 
            sum += s[i];
        return sum;
    }

      - 修改: 修改元素数据并同步更新树状数组的值.(logN)

    //原始数组可以直接修改, 更新树状数组需要将包含 a[i]的所有元素更新.
    // @param index: 修改的元素的下标. a[i]的修改对s[i]以前的元素没有影响.
    // @param dalta : 修改量
    void modify(int index, int delta){
        for (int j = index; j <= MAX_N; j += lowbit(j))
            s[j] += delta;
    }
  • 相关阅读:
    mysql数据库基本操作sql语言
    asp.net MVC4 表单
    asp.net MVC4 表单
    Mysql字符集设置
    zen Code 支持的代码样式
    sqlserver数据库标注为可疑的解决办法(转)
    SQL Server遍历表的几种方法
    GridView 动态添加绑定列和模板列
    TransactionScope 之分布式配置
    sql server 执行上100mb sql sql sql server 无法执行脚本 没有足够的内存继续执行
  • 原文地址:https://www.cnblogs.com/roger9567/p/4866792.html
Copyright © 2020-2023  润新知