loj#6280. 数列分块入门 4
#6280. 数列分块入门 4
题目:传送门
简要题意:
给出一个长为 n 的数列,以及 n个操作,操作涉及区间加法,区间求和。
题解:
第一反应...线段树...
然后再去想分块:
有点水...也是运用lazy的思想啊,先存一下每一块的和,对于头尾就可以直接加(记得更新分块和),然后中间的块直接把和加上去,随便检查一下细节就搞定了。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 #define qread(x) x=read() 7 using namespace std; 8 typedef long long LL; 9 inline LL read() 10 { 11 LL x=0,f=1;char ch; 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 LL n,a[51000],ba[51000],sum[51000]; 17 LL block,pos[51000]; 18 void update(LL l,LL r,LL c) 19 { 20 for(int i=l;i<=min(pos[l]*block,r);i++)a[i]+=c,sum[pos[l]]+=c; 21 if(pos[l]!=pos[r]) 22 for(int i=(pos[r]-1)*block+1;i<=r;i++) 23 a[i]+=c,sum[pos[r]]+=c; 24 for(int i=pos[l]+1;i<=pos[r]-1;i++)ba[i]+=c; 25 } 26 void sol(LL l,LL r,LL c) 27 { 28 LL ans=0; 29 for(int i=l;i<=min(pos[l]*block,r);i++)ans+=a[i]+ba[pos[l]]; 30 if(pos[l]!=pos[r]) 31 for(int i=(pos[r]-1)*block+1;i<=r;i++) 32 ans+=a[i]+ba[pos[r]]; 33 for(int i=pos[l]+1;i<=pos[r]-1;i++)ans+=sum[i]+block*ba[i]; 34 printf("%lld\n",ans%(c+1)); 35 } 36 int main() 37 { 38 qread(n);for(int i=1;i<=n;i++)qread(a[i]); 39 block=LL(sqrt(n)); 40 for(int i=1;i<=n;i++) 41 { 42 pos[i]=(i-1)/block+1; 43 sum[pos[i]]+=a[i]; 44 } 45 for(int i=1;i<=n;i++) 46 { 47 int opt,l,r,c;qread(opt);qread(l);qread(r);qread(c); 48 if(opt==0)update(l,r,c); 49 else sol(l,r,c); 50 } 51 return 0; 52 }