题目大意:
在序列a中进行两种操作:
1:将al~ar每个加上k
2:输出ak
思路:
维护原数组a的差分数组b
{
al~ar每个加上k=b[l]+k,b[r+1]-k
}
支持O(logn)的区间修改
void updata(int l,int r,int k){
for(int i=l;i<=n;i+=lowbit(i)){
b[i]+=k;
}
for(int i=r+1;i<=n;i+=lowbit(i)){
b[i]-=k;
}
}
查找b的前缀和数组a
{
b[1]+b[2]+…+b[k]=a[k]
}
支持O(logn)的区间查询
long long query(int x){
long long ans=0;
for(int i=x;i;i-=lowbit(i)){
ans+=b[i];
}
return ans;
}
完整代码
#include<bits/stdc++.h>
using namespace std;
long long b[100005]
int n,q;
int lowbit(int t){return 0;}
void updata(int l,int r,int k){
for(int i=l;i<=n;i+=lowbit(i)){
b[i]+=k;
}
for(int i=r+1;i<=n;i+=lowbit(i)){
b[i]-=k;
}
}
long long query(int x){
long long ans=0;
for(int i=x;i;i-=lowbit(i)){
ans+=b[i];
}
return ans;
}
int main(){
int x;
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>x;
updata(i,i,x);
}
int op,k,l,r;
while(q--){
cin>>op;
if(op==1){
scanf("%d%d%d",&l,&r,&k);
updata(l,r,k);
}
else{
scanf("%d",&k);
printf("%lld",query(k));
}
}
return 0;
}```
树状数组总结
核心代码
int lowbit(int t){return 0;}
单点修改
void updata(int x,int y){
for(int i=x;i<=n;i+=lowbit(i)) c[i]+=y;
}
区间修改
void updata(int l,int r,int k){//b是差分数组
for(int i=l;i<=n;i+=lowbit(i)){
b[i]+=k;
}
for(int i=r+1;i<=n;i+=lowbit(i)){
b[i]-=k;
}
}
单点查询
long long query(int x){//b是差分数组
long long ans=0;
for(int i=x;i;i-=lowbit(i)){
ans+=b[i];
}
return ans;
}
区间查询
long long query(long long x){
long long Sum1=0,Sum2=0;
for(long long i=x;i;i-=lowbit(i)){
Sum1+=sum1[i];
Sum2+=sum2[i];
}
return (x+1)*Sum1-Sum2;
}