树状数组是一种高效的存储方式,可以在nlogn时间内完成数据的更新与查询,下面给出树状数组的c++实现与使用。
首先,树状数组每一位存储的数据是原数组[x-lowbit(x)+1, x]上的总和,其中lowbit(x)是指x二进制最低1位对应的值,如(6)10 = (110)2,其二进制最低1位是第1位,故lowbit(6) = (10)2 = 2。其实现为:
int lowbit(int x) return x & (-x);

树状数组构建如下:

  class FenwickTree{

    private:

      vector<int> tree;
      int n;
      int lowbit(int x) return x & (-x);

    public:

      // 下面是构建
      FenwickTree(int size){
        n = size;
        tree.resize(n+1, 0);
      }  // 构建空的树状数组
      FenwickTree(const vector<int>& arr){
        n = arr.size();
        tree.resize(n+1, 0);
        for(int i = 0; i < n; i++) update(i+1, arr[i]);
      }  // 依据已有的数组构建树状数组,,从1开始到第n位存储,第0位是0,效率为nlogn
      void update(int i, int value){
        while(i <= n){
          tree[i] += value;
          i += lowbit(i);
        }
      }

      // 下面是查询与修改
      int query(int i){
        int sum = 0;
        while(i > 0){
          sum += tree[i];
          i -= lowbit(i);
        }
        return sum;
      }  // 查询到第i位前缀和
      int rangeQuery(int l, int r){
        if(l > r) return 0;  // [l, r]无定义
        return query(r) - query(l-1);  // 差分
      }  // 查询[l, r]上总和
      int get(int i){
        return query(i) - query(i-1);  // 差分
      }  // 查询原数组第i位的值
      int set(int i, int value){
        int oldValue = get(i);
        update(i, value - oldValue);
      }
  }

解释:
1.构建中,update函数会把所有包含arr[i]的tree对应位加上arr[i],其中通过i += lowbit(i)跳转到下一区间
2.查询中,通过i -= lowbit(i)跳回到上一个没有公共区间的相邻区间,从而获取i到开头的和
3.rangeQuery和get依据差分实现
4.set(i)中,会计算和原来值的差值,将差值加到所有包含arr[i]的tree相应位置上

posted on 2026-01-17 12:04  KeyuanChen  阅读(1)  评论(0)    收藏  举报