数列分块入门 4 总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Larry1118/article/details/86653929

在这里插入图片描述
这题变得容易了。。。
只要记录一下每个块的总和即可。
左右两边凸出来的暴力搞就可以了。
上标:
感觉别人有毒吧,我跑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\n",query(l,r,c+1));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Larry1118/article/details/86653929