• [线段树] (f) Luogu3373*(线段树模版题)


    (f) Luogu3373 【模板】线段树 2

    如在阅读本文时遇到不懂的部分,请在评论区询问,或跳转 线段树总介绍

    这题多出了一个乘法,显然须要在开一个乘法的tag

    此时pushdown——线段树的核心操作就难写了许多

    考虑乘法tag的维护

    假设当前区间和为v,加法tag为pt , 下传的变化值为 乘法mk 

    若先乘法后加法 

    v=v*mk+pt*mk

    若先加法后乘法

    v=(v+pt)*mk

    显然(雾)第二种好写,据说第一种可以写但不好写

    那就第二种吧...

    乘法tag与加法乘法tag,和v的关系都可以很容易推出

    附注:

      1. (a+=b)%=p等价于 a+=b,a%=p;同理可以更多括号

      2. plus -> 加法    mul  ->乘法

    代码

    /*luogu3373*/
    /*多%避免爆栈*/
    /*(a+=b)%=p*/
    
    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<cstring>
    #include<string>
    #include<cctype>
    using namespace std;
    typedef long long LL;
    inline LL rd(){
        char c=getchar();LL x=0;bool f=true;
        while(!isdigit(c)){if(c=='-')f=false;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?x:-x;
    }
    const LL N=1e7+3;
    LL n,m,p,a[N];
    struct node{LL l,r,v,mt,pt;}t[N<<2];
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    #define mid (t[rt].l+t[rt].r>>1)
    #define pushup(rt) (t[rt].v=t[ls].v+t[rs].v)%=p
    #define len(rt) (t[rt].r-t[rt].l+1)
    void build(LL rt,LL l,LL r){
        t[rt].l=l,t[rt].r=r,t[rt].mt=1,t[rt].pt=0;
        if(l==r){t[rt].v=a[l]%p;return;}
        build(ls,l,mid);build(rs,mid+1,r);
        pushup(rt);
    }
    void pushdown(LL rt){
        if(t[rt].pt==0&&t[rt].mt==1)return;
        (t[ls].v*=t[rt].mt)%=p; 
        (t[rs].v*=t[rt].mt)%=p;
        (t[ls].pt*=t[rt].mt)%=p; 
        (t[rs].pt*=t[rt].mt)%=p;
        (t[ls].mt*=t[rt].mt)%=p;
        (t[rs].mt*=t[rt].mt)%=p;
        
        (t[ls].v+=t[rt].pt*len(ls))%=p; 
        (t[rs].v+=t[rt].pt*len(rs))%=p;
        (t[ls].pt+=t[rt].pt)%=p; 
        (t[rs].pt+=t[rt].pt)%=p;
        t[rt].pt=0,t[rt].mt=1;
        /*t[ls].v = (t[ls].v*t[rt].mt + t[rt].pt*len(ls)) %p;
        t[rs].v = (t[rs].v*t[rt].mt + t[rt].pt*len(rs)) %p;
        
        t[ls].mt=(t[ls].mt*t[rt].mt)%p;
        t[rs].mt=(t[rs].mt*t[rt].mt)%p;
        t[ls].pt=(t[ls].pt*t[rt].mt+t[rt].pt)%p;
        t[rs].pt=(t[rs].pt*t[rt].mt+t[rt].pt)%p;
    
        t[rt].mt=1,t[rt].pt=0;*/
    }
    void upd_M(LL rt,LL x,LL y,LL k){
        if(x<=t[rt].l&&y>=t[rt].r){(t[rt].pt*=k)%=p;(t[rt].mt*=k)%=p;(t[rt].v*=k)%=p;return;}
        pushdown(rt);
        if(x<=mid)upd_M(ls,x,y,k);
        if(y>mid)upd_M(rs,x,y,k);
        pushup(rt);
    }
    void upd_P(LL rt,LL x,LL y,LL k){
        if(x<=t[rt].l&&y>=t[rt].r){(t[rt].pt+=k)%=p;(t[rt].v+=len(rt)*k)%=p;return;}
        pushdown(rt);
        if(x<=mid)upd_P(ls,x,y,k);
        if(y>mid)upd_P(rs,x,y,k);
        pushup(rt);
    }
    LL query(LL rt,LL x,LL y){
        if(x<=t[rt].l&&y>=t[rt].r)return t[rt].v%p;
        LL res=0;pushdown(rt);
        if(x<=mid)(res+=query(ls,x,y))%=p;
        if(y>mid)(res+=query(rs,x,y))%=p;
        return res;
    }
    int main(){
        n=rd(),m=rd(),p=rd();
        for(LL i=1;i<=n;++i)a[i]=rd();
        LL ty,x,y,k;build(1,1,n);
        while(m--){
            ty=rd(),x=rd(),y=rd();
            switch(ty){
                case 1:
                    k=rd();
                    upd_M(1,x,y,k%p);
                    break;
                case 2:
                    k=rd();
                    upd_P(1,x,y,k%p);
                    break;
                case 3:
                    printf("%lld
    ",query(1,x,y)%p);
            }
        }
        return 0;
    }

    End

  • 相关阅读:
    iOS
    iOS
    iOS
    Xcodeproject详解
    Swift
    iOS
    iOS
    错误 1 无法将文件“objDebugXXX.exe”复制到“binDebugXXX.exe”。文件“binDebugXXX.exe”正由另一进程使用,因此该进程无法访问该文件
    【转载】SQL注入原理讲解
    在“安装”阶段发生异常。 System.Security.SecurityException: 未找到源,但未能
  • 原文地址:https://www.cnblogs.com/lsy263/p/11228052.html
Copyright © 2020-2023  润新知