[线段树 区间取模] D. The Child and Sequence

Posted 鱼竿钓鱼干

tags:

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

[线段树 区间取模] D. The Child and Sequence

题目

题目链接

思路

区间求和,单点修改,区间取模
区间取和和单点修改比较easy
主要问题是区间取模怎么做,其实和区间开根类似
我们没法对整段区间中每个数字取模后没法立刻得到sum,所以没法直接使用lazy标记
但是我们可以发现,区间取模操作一定次数后有很大概率<mod,不需要操作(具体证明可以看其他博客),因此我们可以通过剪枝优化,维护一个区间最大值,如果区间最大值<mod,那么可以直接跳过这个区间的修改操作,否则直接单点暴力修改即可。
所以也不需要什么lazy标记来区间修改了。

代码

单点修改的时候别忘了修改最大值啊啊啊!

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e5+10;
typedef long long LL;
struct tnode{
        int l,r;
        LL sum,mx;
};
struct Segment_Tree{
        tnode t[MAXN<<2];
        int leaf[MAXN];
        void update(int root){
                int ch=root<<1;
                t[root].sum=t[ch].sum+t[ch+1].sum;
                t[root].mx=max(t[ch].mx,t[ch+1].mx);
        }
        void build(int root,int l,int r,int *A){
                t[root].l=l;t[root].r=r;
                if(l!=r){
                        int mid=(l+r)>>1;
                        int ch=root<<1;
                        build(ch,l,mid,A);
                        build(ch+1,mid+1,r,A);
                        update(root);
                }
                else{
                        t[root].sum=A[l];
                        t[root].mx=A[l];
                        leaf[l]=root;             
                }
        }
        void change(int root,LL x){
                root=leaf[root];
                t[root].sum=t[root].mx=x;
                while(root/=2) update(root);
        }
        void get_mod(int root,int l,int r,LL mod){
                int mid=(t[root].l+t[root].r)>>1;
                int ch=root<<1;
                if(t[root].l==l&&t[root].r==r){
					if(t[root].mx<mod)return;
					if(l==r){
						t[root].sum%=mod;
						t[root].mx=t[root].sum;
						return;
					}
					get_mod(ch,l,mid,mod);
					get_mod(ch+1,mid+1,r,mod);
					update(root);
					return;
                }
                if(r<=mid) get_mod(ch,l,r,mod);
                else if(l>mid) get_mod(ch+1,l,r,mod);
                else{
                    get_mod(ch,l,mid,mod);
                    get_mod(ch+1,mid+1,r,mod);
                }
                update(root);
        }
        LL sum(int root,int l,int r){
                int mid=(t[root].l+t[root].r)>>1;
                int ch=root<<1;
                if(t[root].l==l&&t[root].r==r){
                    return t[root].sum;
                }
                if(r<=mid)return sum(ch,l,r);
                else if(l>mid)return sum(ch+1,l,r);
                else{
                    return sum(ch,l,mid)+sum(ch+1,mid+1,r);
                }
        }
};
Segment_Tree ST;
int n,m,k,op;
LL x;
int a[MAXN];
int main(){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        ST.build(1,1,n,a);
        for(int i=1;i<=m;i++){
                int l,r;
                scanf("%d",&op);
                if(op==1){
                        scanf("%d%d",&l,&r);
                        printf("%lld\\n",ST.sum(1,l,r));
                }
                else if(op==2){
                        scanf("%d%d%lld",&l,&r,&x);
                        ST.get_mod(1,l,r,x);
                }
                else{
                        scanf("%d%lld",&k,&x);
                        ST.change(k,x);
                }
        }
        return 0;
}

以上是关于[线段树 区间取模] D. The Child and Sequence的主要内容,如果未能解决你的问题,请参考以下文章

CodeForces 438D. The Child and Sequence(线段树区间更新)

CF438D The Child and Sequence 线段树

CF438DThe Child and Sequence(线段树)

codeforces438D The Child and Sequence

CF438D The Child and Sequence 线段树

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