[模板题][信息学奥赛一本通]动态求连续区间和 原创
动态求连续区间和
题目来源 《信息学奥赛一本通》,模板题
算法标签 RMQ,线段树
题目描述
给定 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
输入样例:
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
输出样例:
11
30
35
思路
树状数组
适用于查询区域 单点修改
其中最重要的就是a[x]的值等于a[x-lowbit(x),x]之间的值累加!
int lowbit(int x){return x&-x;}
lowbit(x)是返回二进制表示下1在第几位的状态,比如 8(2)=1000 10(2)=1010
查询等于通过目标数将所有数字和加起来,求前缀和
因为a[x]只是a[x-lowbit(x),x]的值,因此我们只需要递归累加就可以拿到0到x的前缀和。
int query(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))res+=tr[i];
return res;
}
添加等于添加当前乃至之后所有特殊规律的数字
使得目标前缀和添加的目标大小
int add(int a,int b){for(int i=a;i<=n;i+=lowbit(i))s[i]+=b;}
也就是说 存储的目标位置只与当前值有关 树状图有关 跟实际数据无关!
时间复杂度
求和 n(logn) 浅醉和 o(1)
修改 n(logn) 前缀和 o(n)
参考文献
C++ 代码
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],s[N];//a是正常数组,b是前缀和数组
int n,m;
int lowbit(int x){return x&-x;}
int add(int a,int b){for(int i=a;i<=n;i+=lowbit(i))s[i]+=b;}
int query(int a)
{
int res=0;
for(int i=a;i;i-=lowbit(i))res+=s[i];
return res;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i],add(i,a[i]);
while(m--)
{
int k,a,b;
cin>>k>>a>>b;
if(k)add(a,b);
else cout<<query(b)-query(a-1)<<endl;
}
return 0;
}
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!