zoukankan      html  css  js  c++  java
  • 线段树 在线进行两种不同的修改 洛谷P3373

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

    题意:线段树操作,操作一区间内每个数乘k,操作二区间每个数+k,操作三查询区间数的和(还会输入一个p,要求的是模p后的结果)

    分析:要用到两个update函数,两种lazytag这个很容易想到了,但是pushdown函数的书写却很头疼,不知道一会加一会乘该怎么标记下传

    我们仔细分析会发现,当进行加法操作时,加法优先级低,只改变自身lazytag即可

    进行乘法操作时,乘法优先级高,会同时改变加法和乘法的lazytag

    故我们在标记下传的时候先进行乘法再进行加法

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf=1<<30;
    const int maxn=1e5+7;
    const double pi=acos(-1);
    const int mod=100;
    #define meminf(a) memset(a,0x3f,sizeof(a))
    #define mem0(a) memset(a,0,sizeof(a))
    #define ls rt<<1
    #define rs rt<<1|1
    #define mid (l+r)>>1
    ll dat[maxn<<2],a[maxn<<2],lazyadd[maxn<<2],lazymul[maxn<<2];
    int n_,m,p;
    
    void pushup(int rt){
        dat[rt]=(dat[ls]+dat[rs])%p;
    }
    
    void pushdown(int rt,int l,int r){
        dat[ls]=((dat[ls]*lazymul[rt])%p+lazyadd[rt]*(r-l)/2+p)%p;
        dat[rs]=((dat[rs]*lazymul[rt])%p+lazyadd[rt]*(r-l)/2+p)%p;
        lazymul[ls]=(lazymul[rt]*lazymul[ls])%p;
        lazymul[rs]=(lazymul[rt]*lazymul[rs])%p;
        lazyadd[ls]=((lazymul[rt]*lazyadd[ls])%p+lazyadd[rt]+p)%p;
        lazyadd[rs]=((lazymul[rt]*lazyadd[rs])%p+lazyadd[rt]+p)%p;
        lazyadd[rt]=0;
        lazymul[rt]=1;
    }
    
    void build(int l,int r,int rt){
        lazymul[rt]=1,lazyadd[rt]=0;
        if(l==r-1){
            dat[rt]=a[l];
            return;
        }
        build(l,mid,ls);
        build(mid,r,rs);
        pushup(rt);
    }
    //我们设的乘法优先级高于加法,所以这里要一并更新加法的 
    void update1(int l,int r,int s,int t,int rt,ll c){
        if(s<=l&&r<=t){
            dat[rt]=(dat[rt]*c)%p;
            lazymul[rt]=(lazymul[rt]*c)%p;
            lazyadd[rt]=(lazyadd[rt]*c)%p;
            return;//这里是关键 
        }
        pushdown(rt,l,r);//递归到子节点前先标记下传 
        if(s<mid) update1(l,mid,s,t,ls,c);
        if(t>mid) update1(mid,r,s,t,rs,c);
        pushup(rt);
    }
    
    void update2(int l,int r,int s,int t,int rt,ll c){
        if(s<=l&&r<=t){
            dat[rt]=(dat[rt]+c*(r-l)+p)%p;
            lazyadd[rt]=(lazyadd[rt]+c+p)%p;
            return;//这里是关键 
        }
        pushdown(rt,l,r);//递归到子节点前先标记下传 
        if(s<mid) update2(l,mid,s,t,ls,c);
        if(t>mid) update2(mid,r,s,t,rs,c);
        pushup(rt);
    }
    
    ll query(int l,int r,int s,int t,int rt){
        ll ans=0;
        if(s<=l&&r<=t){
            return (dat[rt]+p)%p;
        }
        pushdown(rt,l,r);
        if(s<mid) ans=(ans+query(l,mid,s,t,ls))%p;
        if(t>mid) ans=(ans+query(mid,r,s,t,rs))%p;
        return ans;
    }
    
    int main(){
          scanf("%d%d%d",&n_,&m,&p);
          int n=1;
          for(int i=1;i<=n_;i++)scanf("%lld",&a[i]);
          while(n<n_)n<<=1;
          build(1,n+1,1);
          for(int i=1;i<=m;i++){
              int opt,x,y;ll k;
              scanf("%d%d%d",&opt,&x,&y);
              if(opt==1){
                  scanf("%lld",&k);
                  update1(1,n+1,x,y+1,1,k);
              }
            else if(opt==2){
                scanf("%lld",&k);
                update2(1,n+1,x,y+1,1,k);
            }
            else if(opt==3){
                printf("%lld
    ",query(1,n+1,x,y+1,1)%p);
            }  
          }
        return 0;
    }
  • 相关阅读:
    CSS-DAY03
    Java语言支持的8种基本数据类型
    Linux目录结构
    面向对象的四个基本特征
    使用AVADA头部有搜索icon怎么去掉?
    在ubuntu 上使用apt-get安装 任意版本
    ubuntu 14.04 nginx 1.12.2 配置https遇见的坑
    java Process执行linux命令
    node.js 接收上传的文件
    node.js 进行http get 向服务端请求
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11381625.html
Copyright © 2011-2022 走看看