【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;
}
待到再迷茫时回头望,所有脚印会发出光芒