zoukankan      html  css  js  c++  java
  • 【洛谷5309】[Ynoi2011] 初始化(分块)

    点此看题面

    大致题意: 两种操作,区间求和,将形如(ax+y)的位置的元素值加(z)

    分块

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

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

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

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

    这有点难描述,而且我语文不好,因此直接看代码吧(代码有注释)。

    (P.S.)(hl666)大佬说,似乎这里不用(sqrt n)作为临界值而用常量(40)更优?

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 200000
    #define SN 30
    #define X 1000000007
    #define min(x,y) ((x)<(y)?(x):(y))
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    #define XSum(x,y) ((x)+(y)>=X?(x)+(y)-X:(x)+(y))
    #define XSub(x,y) ((x)<(y)?(x)-(y)+X:(x)-(y))
    using namespace std;
    int n,a[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void writeln(Con Ty& x) {write(x),pc('
    ');}
    		I void clear() {fwrite(FO,1,C,stdout),C=0;}
    }F;
    class LargeBlock//对于大的情况
    {
    	private:
    		#define SZ 450
    		#define P(x) (((x)-1)/Bs+1)
    		int Bs,p[N+5],a[N+5],s[SZ+5];
    	public:
    		I void Init(CI x,int* v) {Bs=sqrt(x);for(RI i=1;i<=n;++i) Inc(s[p[i]=P(i)],a[i]=v[i]);}//初始化
    		I void U(CI x,CI y,CI v) {for(RI i=y;i<=n;i+=x) Inc(a[i],v),Inc(s[p[i]],v);}//修改,相当于若干单点修改
    		I int Q(CI l,CI r)//区间求和
    		{
    			RI i,t=0;if(p[l]==p[r]) {for(i=l;i<=r;++i) Inc(t,a[i]);return t;}
    			for(i=p[l]*Bs;i>=l;--i) Inc(t,a[i]);for(i=(p[r]-1)*Bs+1;i<=r;++i) Inc(t,a[i]);
    			for(i=p[l]+1;i^p[r];++i) Inc(t,s[i]);return t;
    		}
    }B;
    class SmallBlock//对于小的情况
    {
    	private:
    		int n,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) Inc(a[i],v);}//暴力维护前缀和
    		I int Q(CI x,CI y)
    		{
    			RI t=1LL*(y-x+1)/n*a[n-1]%X,tx=x%n,ty=y%n;//先求出若干完整块的值
    			if(x+(y-x+1)/n*n>y) return t;//若不存在不完整块直接返回
    			tx<=ty?Inc(t,XSub(a[ty],tx?a[tx-1]:0))://如果连成一段
    			Inc(t,XSum(XSub(a[n-1],tx?a[tx-1]:0),a[ty]));//如果一半在尾,一半在头
    			return t;
    		}
    }S[SN+5];
    int main()
    {
    	RI Qt,i,op,x,y,z,ans;for(F.read(n,Qt),i=1;i<=n;++i) F.read(a[i]);//读入
    	for(B.Init(n,a),i=1;i<=SN;++i) S[i].Init(i);W(Qt--)
    	{
    		if(F.read(op,x,y),op^2) {F.read(z),x<=SN?S[x].U(y,z):B.U(x,y,z);continue;}//处理修改
    		for(ans=B.Q(x,y),i=1;i<=SN;++i) Inc(ans,S[i].Q(x,y));F.writeln(ans);//处理询问
    	}return F.clear(),0;
    }
    
  • 相关阅读:
    【转】Java中static关键字用法总结
    Java 几种showMessageDialog的表示
    反片语 UVA 156
    【转】本科生如何发表论文
    关于高考
    5-25 朋友圈
    【转】C语言中字符串输入的三种方法
    201508110842_《Javascript权威指南(第六版)——方法借用,私有状态,construct重构和工厂方法》(P225-233)
    201508061158_《移动开发之——样式链表》
    201508061129_《移动开发之——防止触摸移动导致整个界面“露底”》
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5309.html
Copyright © 2011-2022 走看看