一 概念
树状数组顾名思义就是用数组去模拟一个树,我们经常会用数组模拟二叉树,但这和树状数组差别还是挺大的。
从图片可以看出,数组每个元素维护的是一段区间的和,通过lowbit函数就可以算出每个元素维护的区间,原理有些复杂,感兴趣的同学可以自信百度。
lowbit(x)函数是求x最低位1和改位后面的0够成的数的大小,比如 4 的二进制 100,最低位1及其后面的0 是 100,所以lowbit(4) = 4
lowbit(x) = x&-x;
二 步骤
1.构造树状数组
可以将构造一颗树状数组的过程看成 给一颗所有元素都为0的树状树数组 重复进行修改操作,直到构造完成。
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]),add(i,a[i]);
2.区间查询
int lowbit(int x){
return x&-x;
}
void add(int x,int v){
for(int i = x;i<=n;i+= lowbit(i)){
tree[i]+=v;
}
}
3.区间修改
int query(int x){
int sum = 0;
for(int i = x;i;i-= lowbit(i))sum+=tree[i];
return sum;
}
例题
1.动态求连续区间和
给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列[a,b]的连续和。
输入格式
第一行包含两个整数 n 和 m,分别表示数的个数和操作次数。
第二行包含n个整数,表示完整数列。
接下来 m 行,每行包含三个整数k, a, b(k = 0,表示求子数列[a, b]的和;k = 1,表示第 a 个数加b)。
数列从1开始计数。
输出格式
输出若干行数字,表示k=0 时,对应的子数列[a, b]的连续和。
数据范围
1≤n≤100000,
1≤m≤100000,
1≤a≤b≤n,
数据保证在任何时候,数列中所有元素之和均在 int 范围内。
输入样例:
10 5
1 2 3 4 5 6 7 8 9 10
1 1 5
0 1 3
0 4 8
1 7 5
0 4 8
1
2
3
4
5
6
7
输出样例:
11
30
35
1
2
3
ans
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n,m;
int a[N],tree[N];
int lowbit(int x){
return x&-x;
}
void add(int x,int v){
for(int i = x;i<=n;i+= lowbit(i)){
tree[i]+=v;
}
}
int query(int x){
int sum = 0;
for(int i = x;i;i-= lowbit(i))sum+=tree[i];
return sum;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]),add(i,a[i]);
int k, a, b;
while (m -- )
{
scanf("%d%d%d", &k, &a, &b);
if (k == 0) printf("%d\n", query( b) - query(a-1));
else add(a, b);
}
return 0;
}
感谢阅读,希望本文对你有所帮助