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 }

 

转载于:https://www.cnblogs.com/CHerish_OI/p/8580601.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值