题目描述
分块写法。蓝书P224。
对于整段的修改用标记add记录,对于不足整段的修改采取朴素算法。
分块思想可以用“大段维护,局部朴素”来形容。
C++ 代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
const int N=1e5+10;
typedef long long LL;
LL a[N],sum[N],add[N];
int L[N],R[N];
int pos[N];
int n,m,t;
void change(int l,int r,LL d)
{
int p=pos[l],q=pos[r];
if(p==q)
{
for(int i=l;i<=r;i++) a[i]+=d;
sum[p]+=d*(r-l+1);
}
else
{
for(int i=p+1;i<=q-1;i++) add[i]+=d;
for(int i=l;i<=R[p];i++) a[i]+=d;
sum[p]+=d*(R[p]-l+1);
for(int i=L[q];i<=r;i++) a[i]+=d;
sum[q]+=d*(r-L[q]+1);
}
}
LL ask(int l,int r)
{
int p=pos[l],q=pos[r];
LL ans=0;
if(p==q)
{
for(int i=l;i<=r;i++) ans+=a[i];
ans+=add[p]*(r-l+1);
}
else
{
for(int i=p+1;i<=q-1;i++) ans+= sum[i] + add[i] * (R[i] - L[i] + 1);
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);
for(int i=1;i<=t;i++)
{
L[i]=(i-1)*sqrt(n)+1;
R[i]=i*sqrt(n);
}
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];
}
}
while(m--){
char op[3];
int l,r,d;
scanf("%s%d%d",op,&l,&r);
if(op[0]=='C'){
scanf("%d",&d);
change(l,r,d);
}
else printf("%lld\n",ask(l,r));
}
return 0;
}
可持久化的情况