E - 树状数组 1
E - 树状数组 1
题目描述
如题,已知一个数列,你需要进行下面两种操作:
-
将某一个数加上
-
求出某区间每一个数的和
输入格式
第一行包含两个正整数
第二行包含
接下来
-
1 x k
含义:将第 个数加上 -
2 x y
含义:输出区间 内每个数的和
输出格式
输出包含若干行整数,即为所有操作
样例 #1
样例输入 #1
5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
样例输出 #1
14
16
提示
【数据范围】
对于
对于
对于
数据保证对于任意时刻,
样例说明:
故输出结果14、16
题意
已知一个数列,你需要进行下面两种操作:
-
将某一个数加上
-
求出某区间每一个数的和
树状数组解决的基本问题
在一个序列中
思考:朴素算法如何实现?
“鱼和熊掌不可兼得”,如果第一个操作很快,那么第二个操作就会变得很慢
假设我们有m次询问,要看最坏的情况,那么这两种方式复杂度都到达了
通过树状数组,我们可以把两种操作都做到
lowbit函数(前置知识)
定义一个函数
比如:
那么
所以假设一个数的二进制最低位的1在从右往左数的第k位,那么它的lowbit值就是
int lowbit(int x){
return x & -x;
}
原理:
根据计算机补码的性质。
补码就是原码的反码加一
如:
反码:
加一:
可以发现变为反码后 x 与反码数字位每一位都不同, 当反码加1,反码会逢1一直进位直到遇到0,且这个0变成了1,所以这个数最后面构造了一个 100… 串。 只有一个
树状数组的定义
树状数组是一种维护前缀和的数据结构,可以实现
- 与前缀和相同的是,树状数组使用与原数列大小相同的数组即可维护
- 与前缀和不同的是,树状数组的一个位置 i 存储的是从 i 开始,(包括 i)向前
个元素的和
就是最大的可以整除 的 的幂(通过上述 函数可以得到)
树状数组的性质
设树状数组为b
性质1:有上述定义得到
性质2:父节点
(上为树状数组b,下为原数组a)
树状数组单点修改
根据性质2可以改造出对树状数组单点修改的函数
void add(int k,int x){
while(k <= n){ //不能超范围
b[k] += x;
k += lowbit(k); //维护父节点
}
}
注意:空数组本身就是一个树状数组(和均为0),因此原数组输入数据维护树状数组b时可以直接
树状数组区间查询
作差求lr的区间和:sum[1r] - sum[1~l-1]
根据性质1:
LL getsum(int l,int r){
l --;
LL s1 = 0;
while(l){
s1 += b[l];
l -= lowbit(l);
}
LL s2 = 0;
while(r){
s2 += b[r];
r -= lowbit(r);
}
return s2 - s1;
}
最终代码
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define X first
#define Y second
typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e6+10;
const int M = 2e5+10;
int n,m;
int a,b[N];
int lowbit(int x){
return x & -x;
}
void add(int k,int x){
while(k <= n){
b[k] += x;
k += lowbit(k);
}
}
LL getsum(int l,int r){
l --;
LL s1 = 0;
while(l){
s1 += b[l];
l -= lowbit(l);
}
LL s2 = 0;
while(r){
s2 += b[r];
r -= lowbit(r);
}
return s2 - s1;
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= n; i ++ ){
cin >> a;
add(i,a);
}
while(m -- ){
int op;
cin >> op;
if(op == 1){
int k,x;
cin >> k >> x;
add(k,x);
}
else{
int l,r;
cin >> l >> r;
cout << getsum(l,r) << nl;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
solve();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探