Live2D

[线段树] (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\n",query(1,x,y)%p);
        }
    }
    return 0;
}

End

posted @ 2019-07-22 19:57  lsy263  阅读(168)  评论(0编辑  收藏  举报