• 【LOJ6029】「雅礼集训 2017 Day1」市场(线段树裸题)


    点此看题面

    大致题意: 维护序列,支持区间加法,区间除法(向下取整),区间求(min)和区间求和。

    线段树维护区间除法

    区间加法、区间求(min)和区间求和都是线段树基本操作,因此略过不提。

    此题关键在于维护区间除法。

    而这有一个复杂度玄学的做法,即将区间除法转化为区间减法

    可以考虑对于每个区间,记录下其最小值和最大值,若最小值和最大值做区间除法所需减去的数相等,则易证整个区间所需减去的数相等。

    则我们可以将区间([l,r])分成若干个区间,直至区间最小值与最大值相等即可。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define RL Reg LL
    #define Con const
    #define CI Con int&
    #define CL Con LL&
    #define I inline
    #define W while
    #define N 100000
    #define INF 1e9 
    #define LL long long
    #define min(x,y) ((x)<(y)?(x):(y))
    #define max(x,y) ((x)>(y)?(x):(y))
    #define Gmin(x,y) (x>(y)&&(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 f,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,f=1;W(!D) f=c^'-'?1:-1;W(x=tn+(c&15),D);x*=f;}
    		Tp I void write(Ty x) {x<0&&(pc('-'),x=-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;}
    		#undef D
    }F;
    class SegmentTree//线段树
    {
    	private:
    		#define STO l,mid,rt<<1
    		#define ORZ mid+1,r,rt<<1|1
    		#define PU(x) (O[x]=O[x<<1]+O[x<<1|1])//上传信息
    		#define PD(x) (O[x].A&&(O[x<<1]+=O[x].A,O[x<<1|1]+=O[x].A,O[x].A=0))//下传标记
    		#define GV(x,v) (x<0?x-(x+1)/v+1:x-x/v)//求出x在除v之后减去的数
    		static Con int SZ=N;int n,v[N+5];
    		struct Interval//存储区间信息
    		{
    			int L,Mn,Mx,A;LL S;I Interval(CI l=0,CL s=0,CI mn=INF,CI mx=-INF,CI a=0):L(l),S(s),Mn(mn),Mx(mx),A(a){}//构造函数
    			I Interval operator + (Con Interval& t) Con {return Interval(L+t.L,S+t.S,min(Mn,t.Mn),max(Mx,t.Mx));}//合并区间信息
    			I void operator += (CI x) {S+=L*x,Mn+=x,Mx+=x,A+=x;}I void operator /= (CI x) {RI t=GV(Mn,x);*this+=-t;}//更新区间信息
    		}O[N<<2];
    		I void bld(CI l,CI r,CI rt)//建树
    		{
    			if(!(l^r)) return (void)(O[rt]=Interval(1,v[l],v[l],v[l]));
    			RI mid=l+r>>1;bld(STO),bld(ORZ),PU(rt);
    		}
    		I void upt1(CI l,CI r,CI rt,CI ul,CI ur,CI v)//区间加法
    		{
    			if(ul<=l&&r<=ur) return O[rt]+=v;RI mid=l+r>>1;PD(rt);
    			ul<=mid&&(upt1(STO,ul,ur,v),0),ur>mid&&(upt1(ORZ,ul,ur,v),0),PU(rt);
    		}
    		I void upt2(CI l,CI r,CI rt,CI ul,CI ur,CI v)//区间除法
    		{
    			if(ul<=l&&r<=ur&&GV(O[rt].Mn,v)==GV(O[rt].Mx,v)) return O[rt]/=v;RI mid=l+r>>1;PD(rt);
    			ul<=mid&&(upt2(STO,ul,ur,v),0),ur>mid&&(upt2(ORZ,ul,ur,v),0),PU(rt);
    		}
    		I LL qry1(CI l,CI r,CI rt,CI ql,CI qr)//区间求Min
    		{
    			if(ql<=l&&r<=qr) return O[rt].Mn;RI mid=l+r>>1;RL t=INF;PD(rt);
    			return ql<=mid&&(p=qry1(STO,ql,qr),Gmin(t,p)),qr>mid&&(p=qry1(ORZ,ql,qr),Gmin(t,p)),t;
    		}
    		I LL qry2(CI l,CI r,CI rt,CI ql,CI qr)//区间求和
    		{
    			if(ql<=l&&r<=qr) return O[rt].S;RI mid=l+r>>1;RL t=0;PD(rt);
    			return ql<=mid&&(t+=qry2(STO,ql,qr)),qr>mid&&(t+=qry2(ORZ,ql,qr)),t;
    		}
    	public:
    		I void Init(CI len,int* s) {for(RI i=1;i<=len;++i) v[i]=s[i];bld(1,n=len,1);}
    		I void Add(CI l,CI r,CI v) {upt1(1,n,1,l,r,v);}I void Div(CI l,CI r,CI v) {upt2(1,n,1,l,r,v);}
    		I int QMin(CI l,CI r) {return qry1(1,n,1,l,r);}I LL QSum(CI l,CI r) {return qry2(1,n,1,l,r);}
    }S;
    int main()
    {
    	RI Qtot,i,op,x,y,v;for(F.read(n,Qtot),i=1;i<=n;++i) F.read(a[i]);
    	S.Init(n,a);W(Qtot--)
    	{
    		switch(F.read(op,x,y),++x,++y,op)
    		{
    			case 1:F.read(v),S.Add(x,y,v);break;case 2:F.read(v),S.Div(x,y,v);break;
    			case 3:F.writeln(S.QMin(x,y));break;case 4:F.writeln(S.QSum(x,y));break;
    		}
    	}return F.clear(),0;
    }
    
  • 相关阅读:
    深入浅出设计模式——命令模式(Command Pattern)
    深入浅出设计模式——职责链模式(Chain of Responsibility Pattern)
    深入浅出设计模式——代理模式(Proxy Pattern)
    深入浅出设计模式——享元模式(Flyweight Pattern)
    深入浅出设计模式——外观模式(Facade Pattern)
    perl字符串操作符
    perl中单引号和双引号字符串区别
    用例图详解
    perl中system函数和反引号` `使用区别
    window cmd命令行下执行perl语句
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/LOJ6029.html
Copyright © 2020-2023  润新知