CF438D The Child and Sequence

Posted sxy_limit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF438D The Child and Sequence相关的知识,希望对你有一定的参考价值。

一道CF线段树好题.

  • 前置芝士

    1.线段树:一个很有用数据结构.
    2.势能分析:用来证明复杂度,其实不会也没什么关系啦.
  • 具体做法

    不难发现,对于一个数膜一个大于它的数后,这个数至少减少一半,每个数最多只能被膜(log_2N)次,所以就可以暴力修改了,如果当前子树的最大值也比膜数要大,那这个膜数肯定就没什么用了,所以可以再记录一个区间最大值.
  • 代码

#include<bits/stdc++.h>
#define rap(i,first,last) for(int i=first;i<=last;++i)
#define Lson (now<<1)
#define Rson (now<<1|1)
#define Middle ((left+right)>>1)
#define Left Lson,left,Middle
#define Right Rson,Middle+1,right
#define Now nowleft,nowright
using namespace std;
const int maxN=114514;
int N,M;
struct Tree
{
    //注意开long long
    long long max,sum;//线段树维护区间max和区间和
}tree[maxN*4];
long long arr[maxN];
long long maxll(long long a,long long b)//手写max
{
    if(a>b)return a;
    return b;
}
void PushUp(int now)//合并的部分
{
    tree[now].sum=tree[Lson].sum+tree[Rson].sum;
    tree[now].max=maxll(tree[Lson].max,tree[Rson].max);
}
void Build(int now=1,int left=1,int right=N)//建树部分
{
    if(left==right)
    {
        tree[now].max=tree[now].sum=arr[left];//直接赋值
        return;
    }
    Build(Left);
    Build(Right);
    PushUp(now);//建完子树后合并
}
void UpDataAdd(int num,int add,int now=1,int left=1,int right=N)
//单点覆盖操作(不要问为什么是Add,哎....)
{
    if(num<left||num>right)return;
    if(left==right)
    {
        tree[now].max=add;//直接赋值
        tree[now].sum=add;
        return;
    }
    //没有PushDown
    UpDataAdd(num,add,Left);
    UpDataAdd(num,add,Right);
    PushUp(now);
}
void UpDataMod(int nowleft,int nowright,int mod,int now=1,int left=1,int right=N)
//暴力取膜
{
    if(nowright<left||right<nowleft)return;
    if(tree[now].max<mod)return;//已经没有用了
    if(left==right)//叶节点暴力取膜
    {
        tree[now].max%=mod;
        tree[now].sum%=mod;
        return;
    }
    UpDataMod(Now,mod,Left);
    UpDataMod(Now,mod,Right);
    PushUp(now);
}
long long Query(int nowleft,int nowright,int now=1,int left=1,int right=N)//查询区间和
{
    if(nowright<left||right<nowleft)return 0;
    if(nowleft<=left&&right<=nowright)
    {
        return tree[now].sum;
    }
    return Query(Now,Left)+Query(Now,Right);
}
int main()
{
    scanf("%d%d",&N,&M);
    rap(i,1,N)scanf("%lld",&arr[i]);
    Build();
    int check,left,right,mod;
    rap(i,1,M)
    {
        scanf("%d%d%d",&check,&left,&right);
        if(check==1)
        {
            printf("%lld
",Query(left,right));
        }
        if(check==2)
        {
            scanf("%d",&mod);
            UpDataMod(left,right,mod);//直接修改
        }
        if(check==3)
        {
            UpDataAdd(left,right);//直接修改就行了啊
        }
    }
    return 0;
}

以上是关于CF438D The Child and Sequence的主要内容,如果未能解决你的问题,请参考以下文章

CF438D The Child and Sequence 线段树

CF438D The Child and Sequence(线段树)

CF438D The Child and Sequence

CF438D The Child and Sequence

CF438D The Child and Sequence 线段树

codeforces438D The Child and Sequence