题目链接
大概题意
一个数列有两个操作,一个是在【l,r】这个区间内加上一个数,一个适合计算【l,r】区间的和。
解題思路
这个题之前也是做过的,是用线段树写的,今天用分块练一下区间修改,lazy的意义和线段树差不多,就是个懒惰标记。
看了下时间分块和线段树的时间不差很多,但是线段是更优秀一点吧。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn=1e5+7;
int m,n,num,block,belong[maxn],l[maxn],r[maxn];
long long sum[maxn],a[maxn],lazy[maxn];
char s[10];
void init()
{
block=sqrt(n);
num=n/block;
if(n%block)
num++;
for(int i=1; i<=n; i++)
{
l[i]=(i-1)*block+1;
r[i]=i*block;
}
for(int i=1; i<=n; i++)
belong[i]=(i-1)/block+1;
memset(sum,0,sizeof(sum));
for(int i=1; i<=n; i++)
sum[belong[i]]+=a[i];
}
void update(int ll,int rr,long long v)
{
if(belong[ll]==belong[rr])
{
for(int i=ll; i<=rr; i++)
{
a[i]+=v;
sum[belong[i]]+=v;
}
}
else
{
for(int i=ll; i<=r[belong[ll]]; i++)
{
a[i]+=v;
sum[belong[ll]]+=v;
}
for(int i=belong[ll]+1; i<belong[rr]; i++)
lazy[i]+=v;
for(int i=l[belong[rr]]; i<=rr; i++)
{
a[i]+=v;
sum[belong[rr]]+=v;
}
}
}
long long que(int ll,int rr)
{
long long ans=0;
if(belong[ll]==belong[rr])
{
for(int i=ll; i<=rr; i++)
ans+=(a[i]+lazy[belong[ll]]);
}
else
{
for(int i=ll; i<=r[belong[ll]]; i++)
ans+=(a[i]+lazy[belong[ll]]);
for(int i=belong[ll]+1; i<belong[rr]; i++)
ans+=(sum[i]+lazy[i]*(r[i]-l[i]+1));
for(int i=l[belong[rr]]; i<=rr; i++)
ans+=(a[i]+lazy[belong[rr]]);
}
return ans;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%lld",&a[i]);
init();
while(m--)
{
int x,y;
long long z;
scanf("%s",s);
if(s[0]=='Q')
{
scanf("%d %d",&x,&y);
printf("%lld\n",que(x,y));
}
else
{
scanf("%d %d %lld",&x,&y,&z);
update(x,y,z);
}
}
return 0;
}