前缀和
初始化
时间复杂度:O(n),顺序扫描原数组
查询区间和
时间复杂度:O(1),`S[j]-S[i]`即为原数组i到j的区间和
单点修改
时间复杂度:O(n),修改S[i]到S[n]所有值
单点修改时关联性太强,导致修改太慢,弱化关联关系,以加快速度
lowbit函数
lowbit(i) 代表 i 这个数字,二进制表示的最后一位 1 的位权
示例
lowbit(8) = (1000)2 = 8
树状数组
C[i] 代表前 lowbit(i) 项和
前缀和查询
S[i] = S[i-lowbit(i)] + C[i]
如图,S[7] = C[7] + S[6] = C[7] + C[6] + C[4]
单点修改
下一个需要修改的值,i + lowbit(i)
如图,修改原数组 A[5] 的值,需要修改 C[5]、C[6]、C[8] 的值
实现
class FenwickTree {
constructor(nums) {
this.tree = new Array(nums.length + 1).fill(0)
this.init(nums)
}
lowbit(n) {
return n & (-n)
}
init(nums) {
for (let i=1;i<this.tree.length;i++) {
let count = this.lowbit(i)
while(count) {
this.tree[i] += nums[i - count]
count--
}
}
}
// 在原数组下标为index的数值上加x
add(i, x) {
let index = i + 1
while (index <= this.tree.length) {
this.tree[index] += x
index += this.lowbit(index)
}
}
query(i) {
let index = i + 1
let sum = 0
while (index) {
sum += this.tree[index]
index -= this.lowbit(index)
}
return sum
}
at(i) {
return this.query(i) - this.query(i - 1)
}
output() {
for(let i=0;i<this.tree.length;i++) {
console.log(this.tree[i])
}
}
}