gitbook-way-to-algorithm
  • Introduction
  • Preface 前言
  • Content 目录
  • MathSymbolTable 数学符号表
  • Chapter-1 BasicKnowledge 第1章 基础知识
    • TimeComplexity 时间复杂度
    • Recursion 递归式
  • Chapter-2 Sort 第2章 排序
    • InsertSort 插入排序
    • BubbleSort 冒泡排序
    • QuickSort 快速排序
    • MergeSort 归并排序
  • Chapter-3 Search 第3章 搜索
    • BinarySearch 二分查找法(折半查找法)
    • AdditionMultiplicationPrinciple 加法乘法原理
    • BruteForce 暴力枚举
    • Recursion 递归
    • BreadthFirstSearch 广度优先搜索
    • BidirectionalBreadthSearch 双向广度搜索
    • AStarSearch A*搜索
    • DancingLink 舞蹈链
  • Chapter-4 DataStructure 第4章 数据结构
    • DisjointSet 并查集
    • PrefixTree(TrieTree) 前缀树
    • LeftistTree(LeftistHeap) 左偏树(左偏堆)
    • SegmentTree 线段树
    • FenwickTree(BinaryIndexedTree) 树状数组
    • BinarySearchTree 二叉查找树
    • AVLTree AVL平衡树
    • RedBlackTree 红黑树
    • SkipList 跳跃表
    • BPlusTree B+树
    • BMinusTree B-树
  • Chapter-5 DynamicProgramming 第5章 动态规划
    • Section-1 LinearDP 第1节 线性动规
      • LongestCommonSubsequence 最长公共子序列
      • LongestIncreasingSubsequence 最长递增子序列
      • BidirectionalSubsequence 双向子序列
      • MaximumContinuousSubsequenceSum 最大连续子序列和
      • LongestPalindromicSubsequence 最长回文子序列
    • Section-2 BagDP 第2节 背包问题
      • 01-Bag 01背包
      • CompleteBag 完全背包
      • TwoDimensionBag 二维背包
    • Section-3 RegionalDP 第3节 区域动规
      • MinimumMergeCost - 最小合并代价
      • UniquePath 唯一路径
      • TrianglePath 三角形路径
    • Section-4 TreeDP 第4节 树形动规
      • MaximumBinaryTree 最大二叉树
      • MaxMultipleTree 最大多叉树
      • MaximumBinaryTreeRadiusSum 最大二叉树和
  • Chapter-6 GraphTheory 第6章 图论
    • Section-1 Traverse 第1节 遍历
      • DepthFirstSearch 深度优先搜索
      • BreadthFirstSearch 广度优先搜索
      • TopologicalSort 拓扑排序
      • EulerCycle 欧拉回路
    • Section-2 MinSpanningTree 第2节 最小生成树
      • Kruskal Kruskal算法
      • Prim Prim算法
    • Section-3 ShortestPath 第3节 最短路径
      • BellmanFord BellmanFord算法
      • Dijkstra Dijkstra算法
      • FloydWarshall FloydWarshall算法
      • DifferentConstraints 差分约束
    • Section-4 StronglyConnectedComponents 第4节 强连通分支
      • Kosaraju Kosaraju算法
      • Tarjan Tarjan算法
      • 2-SAT 2-SAT问题
    • Section-5 NetworkFlow 第5节 网络流
      • EdmondsKarp EdmondsKarp算法(最短路径增广算法)
      • PushRelabel 压入与重标记算法
      • Dinic - Dinic算法
      • MinimumCostFlow - 最小费用流
      • MultipleSourceMultipleSinkMaxflow - 多源点多汇点最大流
    • Section-6 BinaryMatch 第6节 二分匹配
      • Hungarian 匈牙利算法
      • HopcroftKarp Hopcroft-Karp算法
      • MatchToMaxflow 二分匹配转化为最大流
      • KuhnMunkres Kuhn-Munkres算法
      • Introduction-Domination,Independent,Covering,Clique 介绍支配集、独立集、覆盖集和团
      • WeightedCoveringAndIndependentSet 最小点权覆盖和最大点权独立集
      • MinimumDisjointPathCovering 最小不相交路径覆盖
      • MinimumJointPathCovering 最小可相交路径覆盖
      • Coloring 染色问题
  • Chapter-7 CombinatorialMathematics 第7章 组合数学
    • FullPermutation 全排列
    • Combination 组合
    • Permutation 排列
    • PermutationGroup 置换群
  • Chapter-8 NumberTheory 第8章 数论
    • PrimeSieve 素数筛法
    • GreatestCommonDivisor 最大公约数
    • Euclid 欧几里得算法
    • ExtendedEuclid 扩展欧几里得算法
    • ChineseRemainerTheorem 中国剩余定理
    • ModularExponentiation 模幂运算
  • Chapter-9 LinearAlgebra 第9章 线性代数
    • Section-1 Matrix 第1节 矩阵
      • Strassen Strassen算法
      • GaussElimination 高斯消元法
      • LUP LUP分解
      • InverseMatrix 矩阵求逆
    • Section-2 LinearProgramming 第2节 线性规划
      • Simplex 单纯形算法
      • Dinkelback Dinkelback算法
  • Chapter-10 AnalyticGeometry 第10章 解析几何
    • Section-1 Polygon 第1节 多边形
      • Cross 向量叉积
      • SegmentIntersection 线段相交
      • Sweeping 扫除算法
      • ConvexPolygonArea 凸多边形面积
      • ConvexPolygonGravityCenter 凸多边形重心
      • NearestNeighbor 最近点对
    • Section-2 ConvexHull 第2节 凸包
      • GrahamScan Graham扫描算法
      • QuickHull 快速凸包算法
      • RotatingCalipers 旋转卡壳
  • Chapter-11 PatternMatch 第11章 文本匹配
    • SimpleMatch 简单匹配
    • AhoCorasickAutomata AC自动机
    • KnuthMorrisPratt KMP匹配算法
    • RabinKarp RabinKarp算法
    • BoyerMoore BoyerMoore算法
  • Chapter-12 GameTheory 第12章 博弈论
    • BashGame 巴什博弈
    • WythoffGame 威佐夫博弈
    • NimGame 尼姆博弈
Powered by GitBook
On this page
  • 树状数组(二进制索引树)
  • 二进制索引树
  • 源码
  • 测试
  1. Chapter-4 DataStructure 第4章 数据结构

FenwickTree(BinaryIndexedTree) 树状数组

PreviousSegmentTree 线段树NextBinarySearchTree 二叉查找树

Last updated 6 years ago

树状数组(二进制索引树)

给定nnn个数字s=[x1,x2,x3,…,xn]s = [x_{1}, x_{2}, x_{3}, \dots, x_{n}]s=[x1​,x2​,x3​,…,xn​],求区间s[p,q)s[p,q)s[p,q)(其中1≤p<q≤n1 \leq p \lt q \leq n1≤p<q≤n)上的所有成员之和(简称区域和/区间和)

∑i=pq−1xi\sum_{i=p}^{q-1} x_ii=p∑q−1​xi​

其中0≤p<q<n0 \leq p \lt q \lt n0≤p<q<n。该区间可以修改任意元素的值。

区间上任意位置s[i]s[i]s[i]的值可以修改,但所有元素都恒为非负整数。

循环累加数组的算法和Segment Tree算法都可以解决该问题,Fenwick树(树状数组/二进制索引树)与Segment Tree同样在时间复杂度O(log2n)O(log_2 n)O(log2​n)内求出某个区域上的和,但空间复杂度更低。实际上由于字节操作,FenwickTree不但占用内存少,且速度更快(内存更紧凑的软件速度更快)。

设sum(n)=∑i=1ns[i]sum(n) = \sum_{i=1}^{n} s[i]sum(n)=∑i=1n​s[i],那么s[p,q)s[p,q)s[p,q)的区间和可以表示为sum(q−1)−sum(p−1)sum(q-1) - sum(p-1)sum(q−1)−sum(p−1)。本问题可以转化为求区间sss上前nnn个元素之和的问题。

任意非负整数都可以表示为222的次方和,比如3=21+20,7=22+21+20,8=233 = 2^1 + 2^0, 7 = 2^2 + 2^1 + 2^0, 8 = 2^33=21+20,7=22+21+20,8=23。所以任意非负整数可以用一个代表bit的数组表示:3=[0,0,1,1]3 = [0, 0, 1, 1]3=[0,0,1,1],7=[0,1,1,1]7 = [0, 1, 1, 1]7=[0,1,1,1],8=[1,0,0,0]8 = [1, 0, 0, 0]8=[1,0,0,0],即二进制数字0011,0111,10000011, 0111, 10000011,0111,1000。那么区域sss可以用nnn个二进制数组来表示所有数字,用Fenwick树结构来表示:

引入最低有效位lowbit函数来构造Fenwick树上的每个节点。lowbitlowbitlowbit是一个非负整数的二进制数字中,最低的非000位的数字(比如lowbit3=1,lowbit6=2,lowbit8=8,lowbit11=1lowbit_{3} = 1, lowbit_{6} = 2, lowbit_{8} = 8, lowbit_{11} = 1lowbit3​=1,lowbit6​=2,lowbit8​=8,lowbit11​=1,显然奇数有lowbitord≡1lowbit_{ord} \equiv 1lowbitord​≡1):

令Fenwick树上的节点xxx存储值

t[x]=∑i=x−lowbit(x)+1xs[i]t[x] = \sum_{i=x-lowbit(x)+1}^{x} s[i]t[x]=i=x−lowbit(x)+1∑x​s[i]

比如

t[1]=∑i=1−1+11s[i]=∑i=11s[i]=s[1]x=1t[2]=∑i=2−2+12s[i]=∑i=12s[i]=s[1]+s[2]x=2t[3]=∑i=3−1+13s[i]=∑i=33s[i]=s[3]x=3t[4]=∑i=4−4+14s[i]=∑i=14s[i]=s[1]+⋯+s[4]x=4t[5]=∑i=5−1+15s[i]=∑i=55s[i]=s[5]x=5t[6]=∑i=6−2+16s[i]=∑i=56s[i]=s[5]+s[6]x=6t[7]=∑i=7−1+17s[i]=∑i=77s[i]=s[7]x=7t[8]=∑i=8−8+18s[i]=∑i=18s[i]=s[1]+⋯+s[8]x=8t[9]=∑i=9−1+19s[i]=∑i=19s[i]=s[9]x=9t[10]=∑i=10−2+110s[i]=∑i=910s[i]=s[9]+s[10]x=10t[11]=∑i=11−1+111s[i]=∑i=1111s[i]=s[11]x=11t[12]=∑i=12−4+112s[i]=∑i=912s[i]=s[9]+⋯+s[12]x=12t[13]=∑i=13−1+113s[i]=∑i=1313s[i]=s[13]x=13t[14]=∑i=14−2+114s[i]=∑i=1314s[i]=s[13]+s[14]x=14t[15]=∑i=15−1+115s[i]=∑i=1515s[i]=s[15]x=15t[16]=∑i=16−16+116s[i]=∑i=116s[i]=s[1]+⋯+s[16]x=16⋯\begin{matrix} t[1] & = \sum_{i=1-1+1}^{1} s[i] & = \sum_{i=1}^{1} s[i] & = s[1] & x=1 \\ t[2] & = \sum_{i=2-2+1}^{2} s[i] & = \sum_{i=1}^{2} s[i] & = s[1] + s[2] & x=2 \\ t[3] & = \sum_{i=3-1+1}^{3} s[i] & = \sum_{i=3}^{3} s[i] & = s[3] & x=3 \\ t[4] & = \sum_{i=4-4+1}^{4} s[i] & = \sum_{i=1}^{4} s[i] & = s[1] + \cdots + s[4] & x=4 \\ t[5] & = \sum_{i=5-1+1}^{5} s[i] & = \sum_{i=5}^{5} s[i] & = s[5] & x=5 \\ t[6] & = \sum_{i=6-2+1}^{6} s[i] & = \sum_{i=5}^{6} s[i] & = s[5] + s[6] & x=6 \\ t[7] & = \sum_{i=7-1+1}^{7} s[i] & = \sum_{i=7}^{7} s[i] & = s[7] & x=7 \\ t[8] & = \sum_{i=8-8+1}^{8} s[i] & = \sum_{i=1}^{8} s[i] & = s[1] + \cdots + s[8] & x=8 \\ t[9] & = \sum_{i=9-1+1}^{9} s[i] & = \sum_{i=1}^{9} s[i] & = s[9] & x=9 \\ t[10] & = \sum_{i=10-2+1}^{10} s[i] & = \sum_{i=9}^{10} s[i] & = s[9] + s[10] & x=10 \\ t[11] & = \sum_{i=11-1+1}^{11} s[i] & = \sum_{i=11}^{11} s[i] & = s[11] & x=11 \\ t[12] & = \sum_{i=12-4+1}^{12} s[i] & = \sum_{i=9}^{12} s[i] & = s[9] + \cdots + s[12] & x=12 \\ t[13] & = \sum_{i=13-1+1}^{13} s[i] & = \sum_{i=13}^{13} s[i] & = s[13] & x=13 \\ t[14] & = \sum_{i=14-2+1}^{14} s[i] & = \sum_{i=13}^{14} s[i] & = s[13] + s[14] & x=14 \\ t[15] & = \sum_{i=15-1+1}^{15} s[i] & = \sum_{i=15}^{15} s[i] & = s[15] & x=15 \\ t[16] & = \sum_{i=16-16+1}^{16} s[i] & = \sum_{i=1}^{16} s[i] & = s[1] + \cdots + s[16] & x=16 \\ \cdots \end{matrix}t[1]t[2]t[3]t[4]t[5]t[6]t[7]t[8]t[9]t[10]t[11]t[12]t[13]t[14]t[15]t[16]⋯​=∑i=1−1+11​s[i]=∑i=2−2+12​s[i]=∑i=3−1+13​s[i]=∑i=4−4+14​s[i]=∑i=5−1+15​s[i]=∑i=6−2+16​s[i]=∑i=7−1+17​s[i]=∑i=8−8+18​s[i]=∑i=9−1+19​s[i]=∑i=10−2+110​s[i]=∑i=11−1+111​s[i]=∑i=12−4+112​s[i]=∑i=13−1+113​s[i]=∑i=14−2+114​s[i]=∑i=15−1+115​s[i]=∑i=16−16+116​s[i]​=∑i=11​s[i]=∑i=12​s[i]=∑i=33​s[i]=∑i=14​s[i]=∑i=55​s[i]=∑i=56​s[i]=∑i=77​s[i]=∑i=18​s[i]=∑i=19​s[i]=∑i=910​s[i]=∑i=1111​s[i]=∑i=912​s[i]=∑i=1313​s[i]=∑i=1314​s[i]=∑i=1515​s[i]=∑i=116​s[i]​=s[1]=s[1]+s[2]=s[3]=s[1]+⋯+s[4]=s[5]=s[5]+s[6]=s[7]=s[1]+⋯+s[8]=s[9]=s[9]+s[10]=s[11]=s[9]+⋯+s[12]=s[13]=s[13]+s[14]=s[15]=s[1]+⋯+s[16]​x=1x=2x=3x=4x=5x=6x=7x=8x=9x=10x=11x=12x=13x=14x=15x=16​

那么Fenwick树上每个节点iii覆盖到的区域和如图所示:

设数字xxx用222的次方和表示为:

x=[bit1,bit2,…,bitm]x = [bit_{1}, bit_{2}, \dots, bit_{m}]x=[bit1​,bit2​,…,bitm​]

比如6=[4,2],8=[8],10=[8,2]6 = [4, 2], 8 = [8], 10 = [8, 2]6=[4,2],8=[8],10=[8,2]。那么恰好有

sum(x)=t[x]+sum(x−lowbit(x))sum(x) = t[x] + sum(x - lowbit(x))sum(x)=t[x]+sum(x−lowbit(x))

求非负整数xxx的最低有效位分为以下几步:

(1)(1)(1) 减111使xxx的最低有效位变为0(x−1x - 1x−1),最低有效位之前的那些000变为111,比如1000−1=1111000 - 1 = 1111000−1=111;

(2)(2)(2) 然后异或操作(x⊕(x−1)x \oplus (x-1)x⊕(x−1))就可以将xxx的最低有效位及之前的所有位设置为111,比如1000⊕0111=11111000 \oplus 0111 = 11111000⊕0111=1111;

(3)(3)(3) 最后与原xxx做与操作(x∧(x⊕(x−1))x \wedge (x \oplus (x-1))x∧(x⊕(x−1))),结果即为最低有效位对应的数字;

lowbit函数的C++实现如下

int LowBit(int x) {
    return x & (x ^ (x-1));
}

或者利用反码特性实现

int LowBit(int x) {
    return x & (-x);
}

对于长度为nnn的区域sss,构造Fenwick树的时间复杂度为O(n⋅log2⁡n)O(n \cdot log_2⁡n)O(n⋅log2​⁡n),查询区域和的时间复杂度为O(log2n)O(log_2 n)O(log2​n),修改区域上一个值的时间复杂度为O(log2⁡n)O(log_2⁡n)O(log2​⁡n),空间复杂度为O(n)O(n)O(n)。

二进制索引树

源码

测试

http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=07BA8E50FC6C41AAE5CFCE28AEB9656E?doi=10.1.1.14.8917&rep=rep1&type=pdf
https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/
FenwickTree.h
FenwickTree.cpp
FenwickTreeTest.cpp
FenwickTree1.png
FenwickTree2.png
FenwickTree4.png