zoukankan      html  css  js  c++  java
  • [线段树] (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

  • 相关阅读:
    Java对象的生命周期与作用域的讨论(转)
    [置顶] Oracle学习路线与方法
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
  • 原文地址:https://www.cnblogs.com/lsy263/p/11228052.html
Copyright © 2011-2022 走看看