题目链接:https://www.acwing.com/problem/content/244/
树状数组大约比分块快上几倍,分块数据结构也具有很强的利用余地,我们这个问题中,没个分块上有两个属性,一个是sum一个是add,其中一个分块的sum域是真实的,但是其中的a[i]是不真实的,真实的a[i]是a[i]+add[pos[i]]。
代码:
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int maxn = 100010; typedef long long ll; int L[maxn],R[maxn]; ll a[maxn],sum[maxn],add[maxn]; int pos[maxn]; int n,m,t; void update(int l,int r,int C){ int p=pos[l],q=pos[r]; if(p==q){ for(int i=l;i<=r;i++)a[i]+=C; sum[p]+=C*(r-l+1); return; }else{ for(int i=p+1;i<=q-1;i++){ sum[i]+=C*(R[i]-L[i]+1); add[i]+=C; } for(int i=l;i<=R[p];i++)a[i]+=C; sum[p]+=C*(R[p]-l+1); for(int i=L[q];i<=r;i++)a[i]+=C; sum[q]+=C*(r-L[q]+1); } } ll query(int l,int r){ ll ans=0; int p=pos[l],q=pos[r]; if(p==q){ for(int i=l;i<=r;i++)ans+=a[i]; ans+=add[p]*(r-l+1); return ans; }else{ for(int i=p+1;i<=q-1;i++)ans+=sum[i]; for(int i=l;i<=R[p];i++)ans+=a[i]; ans+=add[p]*(R[p]-l+1); for(int i=L[q];i<=r;i++)ans+=a[i]; ans+=add[q]*(r-L[q]+1); return ans; } } int main(){ cin>>n>>m; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); //构建分块 t=sqrt(n*1.0); for(int i=1;i<=t;i++){ L[i]=(i-1)*t+1; R[i]=i*t; } if(R[t]<n)++t,L[t]=R[t-1]+1,R[t]=n; //设置分块上的属性,以及每个位置的归属 for(int i=1;i<=t;i++){ for(int j=L[i];j<=R[i];j++){ pos[j]=i; sum[i]+=a[j]; } add[i]=0; } while(m--){ char s[10]; int l,r,d; scanf("%s%d%d",s,&l,&r); if(s[0]=='C'){ scanf("%d",&d); update(l,r,d); }else{ printf("%lld ",query(l,r)); } } return 0; }