【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;
}

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

时间: 2024-08-30 17:48:34

【CF438D】The Child and Sequence(线段树)的相关文章

CF438D The Child and Sequence 线段树

给定数列,区间查询和,区间取模,单点修改. n,m小于10^5 ...当区间最值小于模数时,就直接返回就好啦~ #include<cstdio> #include<iostream> #define R register int #define ls (tr<<1) #define rs (tr<<1|1) using namespace std; inline long long g() { register long long ret=0,fix=1;

CF(438D) The Child and Sequence(线段树)

题意:对数列有三种操作: Print operation l,?r. Picks should write down the value of . Modulo operation l,?r,?x. Picks should perform assignment a[i]?=?a[i] mod x for each i (l?≤?i?≤?r). Set operation k,?x. Picks should set the value of a[k] to x (in other words

Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间求和+点修改+区间取模

D. The Child and Sequence At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks. Fortunately, Picks remembers how to

cf250D. The Child and Sequence(线段树 均摊复杂度)

题意 题目链接 单点修改,区间mod,区间和 Sol 如果x > mod ,那么 x % mod < x / 2 证明: 即得易见平凡, 仿照上例显然, 留作习题答案略, 读者自证不难. 反之亦然同理, 推论自然成立, 略去过程Q.E.D., 由上可知证毕. 然后维护个最大值就做完了.. 复杂度不知道是一个log还是两个log,大概是两个吧(线段树一个+最多改log次.) #include<bits/stdc++.h> #define Pair pair<int, int&g

CodeForces 438D The Child and Sequence(线段树)

题目:http://codeforces.com/problemset/problem/438/D 一个数取模n%m,有两种情况. 1.m>n, n%m=n; 2.m<=n, n%m<=n/2; 所以当m>n时,取模操作可以忽略. 每个a[i]最多需要log(a[i])次取模操作变为0,因此我们可以对所有取模进行暴力更新.最多要更新n*log(a[i])次,由于单次更新复杂度为log(n),所以总复杂度为n*logn*log(a[i]). #include <bits/std

Codeforces Round #250 (Div. 1) D. The Child and Sequence (线段树)

题目链接:http://codeforces.com/problemset/problem/438/D 给你n个数,m个操作,1操作是查询l到r之间的和,2操作是将l到r之间大于等于x的数xor于x,3操作是将下标为k的数变为x. 注意成段更新的时候,遇到一个区间的最大值还小于x的话就停止更新. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5

hdu 4893 Wow! Such Sequence!(线段树)

题目链接:hdu 4983 Wow! Such Sequence! 题目大意:就是三种操作 1 k d, 修改k的为值增加d 2 l r, 查询l到r的区间和 3 l r, 间l到r区间上的所以数变成最近的斐波那契数,相等的话取向下取. 解题思路:线段树,对于每个节点新增一个bool表示该节点以下的位置是否都是斐波那契数. #include <cstdio> #include <cstring> #include <cstdlib> #include <algor

hdu 4893 (多校1007)Wow! Such Sequence!(线段树&amp;二分&amp;思维)

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 352    Accepted Submission(s): 104 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

HDOJ 4893 Wow! Such Sequence! 线段树

http://acm.hdu.edu.cn/showproblem.php?pid=4893 题意:10万的区间,初始都为0,10万次操作,三种操作为单点修改,区间将每个数改成最近的斐波那契数,以及区间求和. 分析:用一个flag记录该段是否被改成斐波那契数,同时多维护一个sum1表示如果该段改成斐波那契数,区间和为多少.开始sum1为区间长度,之后在单点做了修改以后对其更新,需要的时候用其覆盖sum. 1 #include<cstdio> 2 #include<cstring>

HDU4893 Wow! Such Sequence! 线段树

题意:给你一个序列,其中有三种操作 1)位置为K 的数+ D 2)求 l-r 区间和 3)把 l-r 区间里面的所有数都变为理它最近的斐波纳契数 解题思路:这个题的区间更新其实可以在单点更新的时候就得出,为节点维护两个 和,一个是 斐波纳契和 一个是正常和 ,再看这个区间有没有被3覆盖,特判一下就行了. 解题代码: 1 // File Name: 1007.cpp 2 // Author: darkdream 3 // Created Time: 2014年07月29日 星期二 12时49分33