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;
    }

     

  • 相关阅读:
    RN-Android构建失败:Caused by: org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'AwesomeProject'.
    Android更新包下载成功后不出现安装界面
    真机调试: The application could not be installed: INSTALL_FAILED_TEST_ONLY
    react native 屏幕尺寸转换
    Android Studio生成签名文件,自动签名,以及获取SHA1和MD5值
    React Native安卓真机调试
    git提交代码报错Permission denied, please try again
    The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
    命令行设置快捷命令
    Linux 常用指令
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10777983.html
Copyright © 2011-2022 走看看