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

【CF438D】The Child and Sequence(线段树)

点此看题面

大致题意: 给你一个序列,让你支持区间求和、区间取模、单点修改操作。

区间取模

区间求和和单点修改显然都很好维护吧,难的主要是区间取模。

取模标记无法叠加,因此似乎只能暴力搞?

实际上,我么先考虑一个结论:

一个数\(x\)向一个不大于它的数\(p\)取模,所得结果必然小于\(\frac x2\)

证明:

\(p\le\frac x2\)时,由于\(x\%p<p\),所以\(x\%p<\frac x2\)

\(p>\frac x2\)时,由于\(p\le x\),所以\(x\%p=x-p<x-\frac x2<\frac x2\)

所以,这个数减小的速度是非常快的。

同时我们又有一个显然的性质:

一个数\(x\)向一个大于它的数\(p\)取模,所得结果必然为\(x\)本身。

因此,我们可以考虑在原本暴力基础上加一个剪枝:

若取模区间内最大值小于当前模数,就可以直接\(return\)掉。

这样一来,就做完了?

代码

#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 100000
#define LL long long
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==E&&(clear(),0),*C++=c)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
		Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class SegmentTree//线段树
{
	private:
		#define P CI l=1,CI r=n,CI rt=1
		#define L l,mid,rt<<1
		#define R mid+1,r,rt<<1|1
		#define PU(x) (Mx[x]=max(Mx[x<<1],Mx[x<<1|1]),S[x]=S[x<<1]+S[x<<1|1])
		LL Mx[N<<2],S[N<<2];
	public:
		I void Build(P)//建树
		{
			if(l==r) return (void)(Mx[rt]=S[rt]=a[l]);RI mid=l+r>>1;
			Build(L),Build(R),PU(rt);
		}
		I void Mod(CI tl,CI tr,CI X,P)//区间取模
		{
			if(Mx[rt]<X) return;if(l==r) return (void)(Mx[rt]%=X,S[rt]%=X);RI mid=l+r>>1;
			tl<=mid&&(Mod(tl,tr,X,L),0),tr>mid&&(Mod(tl,tr,X,R),0),PU(rt);
		}
		I void Upt(CI x,CI y,P)//单点修改
		{
			if(l==r) return (void)(Mx[rt]=S[rt]=y);RI mid=l+r>>1;
			x<=mid?Upt(x,y,L):Upt(x,y,R),PU(rt);
		}
		I LL Query(CI tl,CI tr,P)//区间求和
		{
			if(tl<=l&&r<=tr) return S[rt];RI mid=l+r>>1;
			return (tl<=mid?Query(tl,tr,L):0)+(tr>mid?Query(tl,tr,R):0);
		}
}S;
int main()
{
	RI Qt,i,op,x,y,z;for(F.read(n,Qt),i=1;i<=n;++i) F.read(a[i]);
	S.Build();W(Qt--) switch(F.read(op,x,y),op)
	{
		case 1:F.writeln(S.Query(x,y));break;
		case 2:F.read(z),S.Mod(x,y,z);break;
		case 3:S.Upt(x,y);break;
	}return F.clear(),0;
}
posted @ 2019-07-19 19:31  TheLostWeak  阅读(179)  评论(0编辑  收藏  举报