@[TOC]([swift刷题模板] 树状数组(BIT/FenwickTree) )
class BIT {
var c: [Int]
var n: Int
init(_ n: Int){
c = Array(repeating:0, count: n + 1)
self.n = n
}
func add(_ i: Int, _ v: Int){
var i = i
while i <= n {
c[i] += v
i += i & -i
}
}
func sum(_ i: Int) -> Int {
var i = i
var s = 0
while i > 0 {
s += c[i]
i &= i - 1
}
return s
}
}
class NumArray {
let tree: BIT
var nums: [Int]
init(_ nums: [Int]) {
tree = BIT(nums.count + 1)
self.nums = nums
for (i, v) in nums.enumerated() {
tree.add(i + 1, v)
}
}
func update(_ index: Int, _ val: Int) {
tree.add(index+1, val - nums[index])
nums[index] = val
}
func sumRange(_ left: Int, _ right: Int) -> Int {
return tree.sum(right + 1) - tree.sum(left)
}
}
例题: 1589. 所有排列中的最大和
这题其实应该用差分数组,可以省一层log。思想就是树状数组的IUPQ模型。
树状数组
经典案例,要用差分数组理解:
这个实际上是用树状数组维护原数组的差分数组c[i]=a[i]-a[i-1]
求原数组的值a[i]实际上是差分数组的前缀sum(c[0]…c[i]),所以get a[i]可以用sum c[i]表示,
而原数组a区间[x,y]更新+v,产生的效果是:x位置比x-1位置大了v,y+1位置比y小了v;
对差分数组c来说,产生变化的就是c[x]增加了v,c[y+1]减小了v,因为c数组代表的是a中每个数比前一个数的差。
题目: P3372 【模板】线段树 1
(式子①)
那么 sigma(a,n) = 式子①
=n*sigma(d,n) - sigma(d2,n)
例题: CF522 D. Closest Equals
这是20220923的茶。
例题: 2407. 最长递增子序列 II
周赛T4,当时用线段树做的;实际测试线段树的表现甚至优于树状数组,奇怪极了。
例题: 6292. 子矩阵元素加 1