树状数组
- 前置知识 :
-
差分&前缀和
-
位运算
-
树的基本概念和定理
1. 什么是树状数组?
树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为Log(N)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在Log(N)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。——百度百科
SMG
其实基本的树状数组就是实现这样一个问题
——求
- 数组中一段区间的和
- 修改数组中某一个数
小明:“不就是前缀和可以搞定的嘛!”
$ \large\texttt{嗖—} $
#include<iostream>
using namespace std;
int a[1000000];
int sum[1000000];
int main()
{
int n, ask;
cin >> n >> ask;
while (ask --)
{
char type;
cin >> type;
if (type == 'A') //查询
{
int x;
cin >> x;
cout << sum[x] << endl;
}
else if (type == 'B') //修改
{
int x, p;
cin >> x >> p;
for (int i = x; i <= n; i ++) sum[i] += p;
}
}
return 0;
}
提交 \large\texttt{提交} 提交
跑得好快呀!
那么这时我们的树状数组就该出场啦~
首先,树状数组,顾名思义长得像树的数组
所以树状数组长这个样
上面是树,下面是数组
首先是求区间和
通过这幅图,应该不难看出,一个数到最前面的距离就等于刚好包含这个区间的几个横条的和:
比如区间1~7为:
绿色条的和
知道这个,那么任意两个数之间的区间也就容易了,
只需要把两个区间到1的区间和相减就可以了。
那有了区间和还不够,还要修改呢
修改也简单,只需要每次修改包含自己的横条就好了(废话)
比如修改5的值:
把蓝色横条全改了就好啦!
这么说两个功能都准备好了,那就到代码实现了
首先引入一个概念——Lowbit
指一个数在二进制下最末尾的1所对应的值
十进制数 | 二进制数 |
---|