[swift刷题模板] 树状数组(BIT/FenwickTree)

@TOC(swift刷题模板 树状数组(BIT/FenwickTree) )

一、 算法&数据结构

1. 描述

二、 模板代码

1. 单点赋值(增加),区间求和(PURQ)

例题: 307. 区域和检索 - 数组可修改

swift 复制代码
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)        
    }
}

  • 以下待施工

2. 区间更新,单点询值(RUPQ)

例题: 1589. 所有排列中的最大和

这题其实应该用差分数组,可以省一层log。思想就是树状数组的IUPQ模型。

树状数组经典案例,要用差分数组理解:

这个实际上是用树状数组维护原数组的差分数组ci=ai-ai-1

求原数组的值ai实际上是差分数组的前缀sum(c0...ci),所以get ai可以用sum ci表示,

而原数组a区间x,y更新+v,产生的效果是:x位置比x-1位置大了v,y+1位置比y小了v;

对差分数组c来说,产生变化的就是cx增加了v,cy+1减小了v,因为c数组代表的是a中每个数比前一个数的差。

  • sumi代替geti,单点求值
  • 两步add(l,v)和add(r+1,-v),区间更新
python 复制代码

3.区间更新,区间求和(RURQ)

题目: P3372 【模板】线段树 1

  • 记sigma(r,i)表示r数组的前i项和。
  • 我们知道,在区间求和的BIT中,实际维护了原数组a的差分数组d。
  • 于是有an = d1+d2+...+dn
  • 观察式子:
    a1+a2+...+an
    = (d1) + (d1+d2) + ... + (d1+d2+...+dn)
    = n * d1 + (n-1) * d2 +... +dn
    = n * (d1+d2+...+dn) - (0 * d1+1 * d2+...+(n-1) * dn) (式子①)
    维护一个数组d2n,其中d2i = (i-1)*di
    每当修改c的时候,就同步修改一下d2,这样复杂度就不会改变

那么 sigma(a,n) = 式子①=n*sigma(d,n) - sigma(d2,n)

python 复制代码

5. 单点更新区间求极值

例题: CF522 D. Closest Equals

这是20220923的茶。

  • 相同元素组成可以看成线段,问题转化为求区间内最短线段。
  • 询问离线,按r排序,计算每个线段长度,记在左端点上。
  • 查询区间最小值即可。
  • 正常用线段树,但是py线段树过不了,于是上网查了个树状数组的模板
python 复制代码

6. 单点赋值,区间询问最大(LIS II)

例题: 2407. 最长递增子序列 II

周赛T4,当时用线段树做的;实际测试线段树的表现甚至优于树状数组,奇怪极了。

python 复制代码

7. 二维树状数组(IUPQ)

例题: 6292. 子矩阵元素加 1

  • 周赛T2,这题卡一维树状数组;但是可以差分过;可以二维树状数或二维差分过。
python 复制代码
相关推荐
TE-茶叶蛋3 分钟前
Next.js中App Router 全部特殊文件一览
开发语言·javascript·网络
红藕香残玉簟秋12 分钟前
【Rust学习】windows安装rust
开发语言·学习·rust
弹简特19 分钟前
【零基础学Python】08-Python面向对象之封装、多态和函数进阶
开发语言·python
人道领域22 分钟前
一篇文章解决Codex的安装,实操一遍过
java·开发语言·codex
thisiszdy28 分钟前
<C++> 智能指针
开发语言·c++
fox_lht30 分钟前
第十四章 一个输入和输出项目:构建一个命令行程序
开发语言·后端·rust
郑州光合科技余经理35 分钟前
海外版外卖系统:如何快速搭建国际化外卖平台
java·开发语言·前端·人工智能·小程序·系统架构·php
Cheng小攸37 分钟前
协议分析与分析工具(一)
开发语言·php
fox_lht40 分钟前
14.2.读文件
开发语言·后端·rust
codeejun40 分钟前
每日一Go-74、Go 云原生可观测性实战之OpenTelemetry 全链路采集:Trace + Metrics + Logs
开发语言·云原生·golang