专栏文章
题解:P3374 【模板】树状数组 1
P3374题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipuxbga
- 此快照首次捕获于
- 2025/12/03 18:21 3 个月前
- 此快照最后确认于
- 2025/12/03 18:21 3 个月前
P3374 【模板】树状数组 1(单点修改,区间查询)
铺垫
我们知道,一个数可以分解成多个 形式的数,也就是说,我们如果要求一个数组前 个数的和,例如我们要求出前六个数的和,只用求出从 长度为 的和与从 长度为 的和并相加就可以求出前六个数的和。
我们知道, 也就是 所以我们只需要求出一个数二进制的末尾 的数量就可以进行拆分从而显著提高查找效率,这里就要引用
int lowbit(int n){return n&(-n);}。也就是求一个数二进制末位的 加上若干个连续的 的二进制数的数值。实现方法

我们可以构建一个如上图的树状数组,很显然,当一个编号为 的节点改变时,编号为 的节点也要相应改变。因此,我们便将编号为 的节点称为编号为 的节点的后继。

以样例为例,我们就可以得到一个这样的初始树状数组。也就是说,一个节点的值是他所有以这个节点为后继的节点的数值之和。修改也同理,只需要将需要修改的节点的所有后继修改就可以了。这样我们就可以得到修改函数了,平均时间复杂度为 。
CPPvoid g(int now,int x){
if(now>n) return;
f[now]+=x;
g(now+lowbit(now),x);
}
查询也同理,如果我们要查询(初始数组)前三个数的和,只需要将树状数组中第二个节点的值与第三个节点的值相加,也就是 ,换言之,我们只需要一直往前搜索编号为 的节点前驱也就是编号为 的数值并求和就是前 个数的和。
CPPunsigned long long co(int x){return x>0?co(x-lowbit(x))+f[x]:0;}
AC代码
CPP#include <bits/stdc++.h>
using namespace std;
unsigned long long f[100000005],n,w,a,b,c,t;
int lowbit(int n){return n&(-n);}
void g(int now,int x){
if(now>n) return;
f[now]+=x;
g(now+lowbit(now),x);
}
unsigned long long co(int x){return x>0?co(x-lowbit(x))+f[x]:0;}
int main(){
cin>>n>>w;
for(int i=1;i<=n;i++){
cin>>t;
g(i,t);
}
for(int i=0;i<w;i++){
cin>>a>>b>>c;
if(a==1){
g(b,c);
}else{
cout<<co(c)-co(b-1)<<endl;
}
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...