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 }

 

posted @ 2018-03-16 13:35  CHerish_OI  阅读(288)  评论(0编辑  收藏  举报