例题:【AcWing 243. 一个简单的整数问题2】
线段树模板题,区间修改区间求和。
题解:
将序列分成N/B块,维护:
id[i] = i/B,i所在块标号
res[id] = 第id块的sum
base[id] = 第id块的add标记
修改时,大块修改base[id],小块修改a[i],同时维护每块的res[id]。询问时,大块使用res[id]信息/小块暴力。
总复杂度O(Q*sqrt(N))。
代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=1e5+9;
int n,B,q;
int a[maxn];
ll res[maxn],base[maxn];
ll query(int l,int r)
{int idl=l/B,idr=r/B;ll ans=0;if(idl==idr){for(int i=l;i<=r;i++){ans+=a[i]+base[idl];} return ans;}else {for(int i=l;i<(idl+1)*B;i++){ans+=a[i]+base[idl];}for(int i=idl+1;i<idr;i++){ans+=res[i];}for(int i=idr*B;i<=r;i++){ans+=a[i]+base[idr];}//每个复杂度都是√N return ans;}
}
void change(int l,int r,int x)
{int idl=l/B,idr=r/B;ll ans=0;if(idl==idr){for(int i=l;i<=r;i++){a[i]+=x;res[idl]+=x;}}else {for(int i=l;i<(idl+1)*B;i++){a[i]+=x;res[idl]+=x;}for(int i=idl+1;i<idr;i++){base[i]+=x;res[i]+=B*x;}for(int i=idr*B;i<=r;i++){a[i]+=x;res[idr]+=x;}//每个复杂度都是√N }
}
int main()
{cin>>n>>q;B=sqrt(n);for(int i=1;i<=n;i++){cin>>a[i];res[i/B]+=a[i];}char op;int l,r,x;while(q--){cin>>op;if(op=='Q'){cin>>l>>r;cout<<query(l,r)<<endl;}else {cin>>l>>r>>x;change(l,r,x);} }return 0;
}