树状数组是一种高效的存储方式,可以在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相应位置上
浙公网安备 33010602011771号