这题变得容易了。。。
只要记录一下每个块的总和即可。
左右两边凸出来的暴力搞就可以了。
上标:
(感觉别人有毒吧,我跑1000ms+,他/她™只跑100ms+。。。 )
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
int a[50010],d[321],n,b[321];
int opt,l,r,c,st;
int bl[50010],le[321],ri[321];
inline int read()
{
int x=0,f=0; char c=getchar();
while (c<'0' || c>'9') f=(c=='-') ? 1:f,c=getchar();
while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return f ? -x:x;
}
void add(int l,int r,int c)
{
for (int i=l;i<=min(ri[bl[l]],r);i++)
a[i]+=c,d[bl[l]]+=c;
if (bl[l]!=bl[r])
{
for (int i=le[bl[r]];i<=r;i++)
a[i]+=c,d[bl[r]]+=c;
}
for (int i=bl[l]+1;i<=bl[r]-1;i++) b[i]+=c;
}
int query(int l,int r,int c)
{
ll ans=0;
for (int i=l;i<=min(ri[bl[l]],r);i++)
ans=(ans+a[i]+b[bl[l]])%c;
if (bl[l]!=bl[r])
{
for (int i=le[bl[r]];i<=r;i++)
ans=(ans+a[i]+b[bl[r]])%c;
}
for (int i=bl[l]+1;i<=bl[r]-1;i++)
ans=(ans+d[i]+(ll)b[i]*(ri[i]-le[i]+1))%c;
return ans;
}
int main()
{
freopen("6280.in","r",stdin);
freopen("6280.out","w",stdout);
n=read();st=sqrt(n);
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=n;i++)
{
bl[i]=(i-1)/st+1;
d[bl[i]]+=a[i];
if (!le[bl[i]]) le[bl[i]]=i;
ri[bl[i]]=i;
}
for (int i=1;i<=n;i++)
{
opt=read(),l=read(),r=read(),c=read();
if (opt==0) add(l,r,c);
else printf("%d
",query(l,r,c+1));
}
return 0;
}