线段树模板2

题目链接:https://www.luogu.org/problemnew/show/P3373

题意:相比与模板1,这题多了一个操作,即将一段区间的数都乘k。因为乘法的优先级高,这里要采用乘法优先。实现上和模板1的差别在于:

    0. 使用两个懒惰值,add表示要加的数,mul表示要乘的数,分别初始化为0,1。

    1. 更新乘法时,要将原来的add也乘上mul。

    2. 向下传递懒惰值时,先乘再加,对孩子的add属性,要先乘父亲的mul,在加父亲的add,孩子的mul直接乘父亲的mul即可。然后将父亲的add置0,mul置1。

    3. 因为乘法和加法对取模运算都是自由的,计算过程可以直接取模。

AC代码:

#include<cstdio>
#include<cctype>
using namespace std;

typedef long long LL;
const int maxn=100005;

inline int read(){
    int x=0,f=0;char c=0;
    while(!isdigit(c)){f|=c=='-';c=getchar();}
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return f?-x:x;
}

inline LL readLL(){
    LL x=0;int f=0;char c=0;
    while(!isdigit(c)){f|=c=='-';c=getchar();}
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return f?-x:x;
}

struct node{
    int l,r;
    LL value,mul,add;
}tr[4*maxn];

LL a[maxn],n,m,P,ans;

void build(int v,int l,int r){
    tr[v].l=l,tr[v].r=r,tr[v].add=0,tr[v].mul=1;
    if(l==r){
        tr[v].value=a[r];
        return;
    }
    int mid=(l+r)>>1;
    build(2*v,l,mid);
    build(2*v+1,mid+1,r);
    tr[v].value=(tr[2*v].value+tr[2*v+1].value)%P;
}

void spread(int v){
    tr[2*v].value=tr[2*v].value*tr[v].mul%P;
    tr[2*v].value=(tr[2*v].value+(tr[2*v].r-tr[2*v].l+1)*tr[v].add)%P;  
    tr[2*v+1].value=tr[2*v+1].value*tr[v].mul%P;
    tr[2*v+1].value=(tr[2*v+1].value+(tr[2*v+1].r-tr[2*v+1].l+1)*tr[v].add)%P;
    tr[2*v].add=tr[2*v].add*tr[v].mul%P;
    tr[2*v].add=(tr[2*v].add+tr[v].add)%P;
    tr[2*v].mul=tr[2*v].mul*tr[v].mul%P; 
    tr[2*v+1].add=tr[2*v+1].add*tr[v].mul%P;
    tr[2*v+1].add=(tr[2*v+1].add+tr[v].add)%P;
    tr[2*v+1].mul=tr[2*v+1].mul*tr[v].mul%P;
    tr[v].mul=1,tr[v].add=0;
}

void update(int v,int l,int r,LL mu,LL ad){
    if(tr[v].l==l&&tr[v].r==r){
        if(ad){
            tr[v].value=(tr[v].value+(tr[v].r-tr[v].l+1)*ad)%P;
            tr[v].add=(tr[v].add+ad)%P;
        }
        else{
            tr[v].value=(tr[v].value*mu)%P;
            tr[v].add=(tr[v].add*mu)%P;
            tr[v].mul=(tr[v].mul*mu)%P;
        }
        return;
    }
    if(tr[v].add||tr[v].mul!=1) spread(v);
    int mid=(tr[v].l+tr[v].r)>>1;
    if(r<=mid){
        update(2*v,l,r,mu,ad);
    }
    else{
        if(l>mid){
            update(2*v+1,l,r,mu,ad);
        }
        else{
            update(2*v,l,mid,mu,ad);
            update(2*v+1,mid+1,r,mu,ad);
        }
    }
    tr[v].value=(tr[2*v].value+tr[2*v+1].value)%P;
}

void query(int v,int l,int r){
    if(tr[v].l==l&&tr[v].r==r){
        ans=(ans+tr[v].value)%P;
        return;
    }
    if(tr[v].add||tr[v].mul!=1) spread(v);
    int mid=(tr[v].l+tr[v].r)>>1;
    if(r<=mid){
        query(2*v,l,r);
    }
    else{
        if(l>mid){
            query(2*v+1,l,r);
        }
        else{
            query(2*v,l,mid);
            query(2*v+1,mid+1,r);
        }
    }
    tr[v].value=(tr[2*v].value+tr[2*v+1].value)%P;
}

int main(){
    n=read(),m=read(),P=readLL();
    for(int i=1;i<=n;++i)
        a[i]=readLL();
    build(1,1,n);
    while(m--){
        int x,y,op=read();
        LL k;
        if(op==1){
            x=read(),y=read(),k=readLL();
            k%=P;
            update(1,x,y,k,0);
        }
        else if(op==2){
            x=read(),y=read(),k=readLL();
            k%=P;
            update(1,x,y,1,k);
        }
        else{
            ans=0;
            x=read(),y=read();
            query(1,x,y);
            printf("%lld
",ans);
        }
    }
    return 0;
}

 

原文地址:https://www.cnblogs.com/FrankChen831X/p/10777983.html