传送门:LOJ#6280. 数列分块入门 4
题意:给出一个长为n的数列,以及n个操作,操作涉及区间加法,区间求和。
和数列分块入门3相比,基本没什么变化。对于区间求和还是整块的进行求,残缺的部分进行暴力枚举。对了不要忘记加上tag[]的值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=5e4+10;
typedef long long ll;
ll a[maxn],n,block,pos[maxn],sum[maxn],tag[maxn];void add(ll l,ll r,ll x){for(ll i=l;i<=min(pos[l]*block,r);i++){a[i]+=x;sum[pos[i]]+=x;}if(pos[l]!=pos[r]){for(ll i=(pos[r]-1)*block+1;i<=r;i++){a[i]+=x;sum[pos[i]]+=x;}}//cout<<"*"<<endl;for(ll i=pos[l]+1;i<pos[r];i++){tag[i]+=x;}}ll query(ll l,ll r,ll x){ll ans=0;for(ll i=l;i<=min(pos[l]*block,r);i++){ans=(ans+a[i]+tag[pos[i]])%x;}if(pos[l]!=pos[r]){for(ll i=(pos[r]-1)*block+1;i<=r;i++){ans=(ans+a[i]+tag[pos[i]])%x;}}for(ll i=pos[l]+1;i<pos[r];i++){ans=(ans+sum[i]+tag[i]*block)%x;}return ans;}int main(){scanf("%lld",&n);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}block=sqrt(n);for(ll i=1;i<=n;i++){pos[i]=(i-1)/block+1;}for(ll i=1;i<=n;i++){sum[pos[i]]+=a[i];}ll opt,l,r,c;for(int i=0;i<n;i++){scanf("%lld%lld%lld%lld",&opt,&l,&r,&c);if(opt==0) add(l,r,c);else printf("%lld\n",query(l,r,c+1));}return 0;
}