CF438DThe Child and Sequence(线段树)

Posted chenxiaoran666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF438DThe 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;

以上是关于CF438DThe Child and Sequence(线段树)的主要内容,如果未能解决你的问题,请参考以下文章