题意
给出个数的数列,有
个操作,操作涉及到区间加法和区间求和,对(
+1)进行取模
思路
区间加法依旧是用数组,区间求和我首先想到的是前缀和,对于每一块我们用前缀和,但是我们对于不完整块都是用暴力解决的,所以我还是放弃了前缀和的方法,设置了一个
数组来统计块的和,如果对于完整的块我们直接加上
和
(block是块的长度),这样的话就可以完成区间求和的操作,好吧,这是线段树可以轻而易举的做到,但这里写的是分块。
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N = 100007;
int l[N],r[N],block,num,belong[N],n,x,y;
ll a[N],lazy[N],b[N];
inline void build()
{
block=sqrt(n);
num=n/block;if (n%num) num++;
for (int i=1;i<=num;i++)
l[i]=(i-1)*block+1,r[i]=i*block;
r[num]=n;
for (int i=1;i<=n;i++)
belong[i]=(i-1)/block+1;
for (int i=1;i<=num;i++)
for (int j=l[i];j<=r[i];j++)
b[i]+=a[j];
//b[i]保存的是第i块的和
}
inline void update(int x,int y,int c)
{
if (belong[x]==belong[y])
{
for (int i=x;i<=y;i++)
a[i]+=c,b[belong[x]]+=c;
return;
}
for (int i=x;i<=r[belong[x]];i++)
a[i]+=c,b[belong[x]]+=c;
for (int i=belong[x]+1;i<belong[y];i++) lazy[i]+=c;
//这里b[i]不需要更新是因为加的数都到lazy数组里面去了
for (int i=l[belong[y]];i<=y;i++)
a[i]+=c,b[belong[y]]+=c;
//a[i]进行更新的时候,b[i]也要更新
}
inline ll ask(int x,int y,ll c)
{
int cnt=0;
ll ans=0,M=c+1;
if (belong[x]==belong[y])
{
for (int i=x;i<=y;i++)
ans=(a[i]+ans+lazy[belong[x]])%M;
return ans;
}
for (int i=x;i<=r[belong[x]];i++)
ans=(a[i]+ans+lazy[belong[x]])%M;
for (int i=l[belong[y]];i<=y;i++)
ans=(a[i]+ans+lazy[belong[y]])%M;
//对于不完整块我们暴力
for (int i=belong[x]+1;i<belong[y];i++)
{
ans=(ans+b[i]+lazy[i]*block)%M;
//ans的操作,每次加上b[i](区间和)和lazy[i]*block
}
return ans;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
#endif
IOS
int m;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
}
build();
for (int k=1;k<=n;k++)
{
int l,r,op;
ll c;
cin>>op>>l>>r>>c;
if (op==0)
update(l,r,c);
else
cout<<ask(l,r,c)<<endl;
}
return 0;
}