zoukankan      html  css  js  c++  java
  • 线段树模板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;
    }

     

  • 相关阅读:
    06_springboot热部署
    05_springboot多配置文件
    04_springBoot端口和上下文路径
    03_springboot错误处理.md
    02_springboot部署-jar和-war的方式
    01_idea创建springboot
    Vue学习笔记
    Java使用Swing实现五子棋。
    我的开源项目
    Java常用库和工具类
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10777983.html
Copyright © 2011-2022 走看看