PrepStack · Markdown HTML

Fenwick Tree / 树状数组

区间查询数据结构 · HTML

数学 / 逻辑形态

支持 add(i,delta) 与 prefix(r)=aggregate(a[0:r]);区间由两个前缀相消。

识别信号

容易误判的相似信号

SignalWhy it is different
复杂区间赋值基础 Fenwick 不自然支持;考虑 lazy segment tree。
不可逆动态聚合动态区间最小值不能由两个前缀相消,应选 segment tree。

核心不变量

1-based tree[i] 保存 (i-lowbit(i),i] 的聚合;查询下降链把前缀拆成互不重叠块。

状态、转移与处理顺序

ItemDefinition
State长度 n+1 的 tree;对外 0-based,下标进入结构时加一。
Transitionadd 反复 i+=lowbit(i) 更新祖先块;prefix 反复 i-=lowbit(i) 收集分解块。
Frontier / order更新前沿向更大祖先块移动;查询前沿清除最低有效位直至 0。

Python 骨架

class Fenwick:
    def __init__(self, n):
        self.n = n
        self.t = [0] * (n + 1)
    def add(self, index, delta):
        i = index + 1
        while i <= self.n:
            self.t[i] += delta
            i += i & -i
    def prefix(self, right):
        total, i = 0, right
        while i:
            total += self.t[i]
            i -= i & -i
        return total
    def range_sum(self, left, right):
        return self.prefix(right) - self.prefix(left)

正确性思路

  1. lowbit 唯一决定每个 tree 单元覆盖的块。
  2. add 访问恰好所有包含该点的块。
  3. prefix 的下降链互不重叠且完整覆盖目标前缀。
  4. 两个前缀相消后只剩 [left,right)。

复杂度

TimeSpaceParameters
更新、前缀和、区间和均 O(log n)O(n)n 为数组长度;逐点构建为 O(n log n)

边界条件

错误模式

PatternWhy it fails / fix
从内部下标 0 更新lowbit(0)=0 会死循环。
端点错一位统一 prefix(r) 为 [0,r)。
把 set 当 add设置新值需添加 new-old。

选择与排除规则

相关模板

RelationTemplateBoundary
离线替代归并排序跨区间计数只需一次关系计数
通用替代线段树区间聚合摘要不可由可逆前缀表达

原创微型例子

环节内容
Result新区间和为 8。
Scenario数组 [2,0,3,1],下标 1 增加 4,再查询 [1,4)。
Walkthroughadd 更新所有含第二项的块;prefix(4)-prefix(1)=10-2。

Recall prompts

我的补充