把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5309】[Ynoi2011] 初始化(根号分治+分块)

题目链接

  • 给定一个长度为 \(n\) 的序列 \(a\)
  • \(q\) 次操作,分为两种:区间求和;将形如 \(kx+y\) 的位置的元素值加 \(z\)\(y\le x\))。
  • \(1\le n,q\le 2\times10^5\)

分块简单题+卡常

那啥,某一天突然发现自己以前的代码被卡掉了,所以在原本基础上卡了卡。发现现在和过去的常数大概有两点差异:

  • 一开始只是单纯将以前的代码改成了现在的码风,似乎变快了一些。
  • 删掉取模优化发现居然真的变慢了,即便如此现在我也懒得去写这种东西了。(然而这题代码被我改成了先全开 long long 最后取模

这种题目显然就是按照 \(x\)\(\sqrt n\) 的大小关系来根号分治。

对于 \(x >\sqrt n\),我们用分块来实现 单点修改,区间求和

对于 \(x\le\sqrt n\),我们考虑枚举 \(x\),则可发现每次询问都由若干长度为 \(x\) 的完整的段和最后一小段不完整的段组成。

那么我们可以对于 \(x\),维护一个前缀和数组,然后每次就相当于求出整段和的若干倍加上剩余部分的和。

具体实现注意常数问题,最好将块长调小一些。

代码:\(O(n\sqrt n)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 200000
#define SN 150
#define X 1000000007
#define LL long long
using namespace std;
namespace FastIO
{
	#define FS 100000
	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('\n');}
}using namespace FastIO;
int n,a[N+5];
class LargeBlock//对于大的情况
{
	private:
		#define SZ 450
		#define P(x) (((x)-1)/Bs+1)
		int sz,bl[N+5];LL a[N+5],s[SZ+5];
	public:
		I void Init(CI x,int* v) {sz=sqrt(x);for(RI i=1;i<=n;++i) bl[i]=(i-1)/sz+1,a[i]=v[i],s[bl[i]]+=v[i];}//初始化
		I void U(CI x,CI y,CI v) {for(RI i=y;i<=n;i+=x) a[i]+=v,s[bl[i]]+=v;}//暴力单点修改
		I int Q(CI l,CI r) Cn//区间求和
		{
			RI L=bl[l],R=bl[r],i;LL t=0;if(L==R) {for(i=l;i<=r;++i) t+=a[i];return t%X;}
			if(L*sz-l+1<=sz/2) for(i=L*sz;i>=l;--i) t+=a[i];else for(t+=s[L],i=(L-1)*sz+1;i^l;++i) t-=a[i];
			if(r-(R-1)*sz<=sz/2) for(i=(R-1)*sz+1;i<=r;++i) t+=a[i];else for(t+=s[R],i=R*sz;i^r;--i) t-=a[i];
			for(i=L+1;i<R;++i) t+=s[i];return t%X;
		}
}B;
class SmallBlock//对于小的情况
{
	private:
		int n;LL a[SN+5];
	public:
		I void Init(CI x) {n=x;}I void U(CI y,CI v) {for(RI i=y%n;i^n;++i) a[i]+=v;}//暴力维护前缀和
		I int Q(CI x,CI y) Cn
		{
			LL t=(y-x+1)/n*a[n-1]%X;RI tx=x%n,ty=y%n;if(x+(y-x+1)/n*n>y) return t%X;//若干完整块的和
			tx<=ty?t+=a[ty]-(tx?a[tx-1]:0):t+=a[n-1]-(tx?a[tx-1]:0)+a[ty];return t%X;//剩余部分的和
		}
}S[SN+5];
int main()
{
	RI Qt,i,op,x,y,z;LL t;for(read(n,Qt),i=1;i<=n;++i) read(a[i]);
	for(B.Init(n,a),i=1;i<=SN;++i) S[i].Init(i);W(Qt--)
	{
		if(read(op,x,y),op^2) {read(z),x<=SN?S[x].U(y,z):B.U(x,y,z);continue;}//处理修改
		for(t=B.Q(x,y),i=1;i<=SN;++i) t+=S[i].Q(x,y);writeln(t%X);//处理询问
	}return clear(),0;
}
posted @ 2019-04-21 20:31  TheLostWeak  阅读(320)  评论(0编辑  收藏  举报