[参考视频](https://www.bilibili.com/video/BV12a411i7rP) ### 一、从普通前缀和引入 * **普通前缀和** 采用$s_n=a_1+a_2+...+a_n$,计算普通前缀和。 * **动态前缀和** 如果在求前缀和的过程中,某个$a_i$修改了,那么原来统计好的$s_i$就不对了,而且可能修改的还不只一个,这样,普通前缀和就不好用了,此时,可以用树状数组来解决。 ### 二、树状数组基础
如上图: $c[1]$管理$a[1]$; $c[2]$管理$c[1],a[2]$; $c[3]$管理$a[3]$; $c[4]$管理$c[2],c[3],a[4]$; $c[i]$管辖区间范围规定
总结:$i$管辖的区间长度,要看$i$的二进制表示法最后有几个$0$,比如有$k$个$0$,它管辖的个数就是$2^k$个。 $$\large 管辖范围: (a[i]-2^k+1) \sim a[i]$$ **举个栗子**:$i=(4)_{10}=(0100)_2$,二进制表示法最后两位是$0$,所以它的管理范围是$2^2=4$,即$a[1]\sim a[4]$。 再来一个,$i=(8)_{10}=(1000)_2$,二进制表示法最后三位是$0$,所以它的管理范围是$2^3=8$,即$a[1]\sim a[8]$。 $c[i]$管辖区间范围计算办法
如上图,我们想要得$i=20$的最后面的几个$0$,也就是求最后面的$100$(红色椭圆里面的数字),可以通过二进制运算的$lowbit$运算就可以得到。 总结:$lowbit$函数可以取得原数二进制表示法中最后一个$1$。 $$\large c[i]区间长度计算办法:lowbit(i)=(-i)\&i$$ 前驱与后继
直接前驱 $$\large c[i-lowbit(i)]$$ 直接后继 $$\large c[i+lowbit(i)]$$ 树状数组下标从1开始,不能从0开始。因为数组长度是$lowbit(i)$,如果从$0$开始,$lowbit(0)=(-i)\&i=0$,那么前驱就是$c[0-0]=c[0]$,就一直不变,死循环。 小结:树状数组下标从$1$开始。 如果我们现在将树状数组记录的是$a[i]$的前缀和数组,那么$$sum[7]=c[7]+c[6]+c[4]$$ 这是因为$c[7]$管着$a[7]$,$c[6]$管着$a[5],a[6]$,$c[4]$管着$a[1],a[2],a[3],a[4]$。 小结:查询找所有前驱,更新改所有后继。 ![6.png](https://cdn.acwing.com/media/article/image/2022/07/09/64630_8c38e0caff-6.png) ![7.png](https://cdn.acwing.com/media/article/image/2022/07/09/64630_8e7398ccff-7.png) 树状数组操作 * 点更新 * 查询前缀 两者都是$O(logn)$的时间复杂度。 假设$n=1e9$,则此时操作次数就是$log10^9=30$,速度极快。 ![8.png](https://cdn.acwing.com/media/article/image/2022/07/09/64630_e38dd464ff-8.png) ### 三、实现代码 ```c++ #include using namespace std; const int N = 1e5 + 10; int n, a[N]; //下面是用树状数组完成前缀和的保存办法 #define lowbit(x) (x & -x) int c[N]; //点更新 void add(int i, int z) { for (; i <= n; i += lowbit(i)) c[i] += z; //更新所有祖先 } //前缀和 int sum(int i) { int s = 0; for (; i; i = i - lowbit(i)) s += c[i]; return s; } //区间和 int sum(int i, int j) { return sum(j) - sum(i - 1); } /* 测试用例: 5 2 3 1 4 5 */ int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); add(i, a[i]); } //利用树状数组求前缀和 printf("%d\n", sum(4)); //利用树状数组求区间和 printf("%d\n", sum(5) - sum(3)); return 0; } ``` ### 四、树状数组应用 #### 1、树状数组求区间最大值 https://blog.csdn.net/weixin_46048848/article/details/108529488