码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-07-19 20:58:51      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:def   std   pre   无法   type   序列   结果   vat   str   

点此看题面

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

区间取模

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

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

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

一个数\(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;
}

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

标签:def   std   pre   无法   type   序列   结果   vat   str   

原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF438D.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!