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;
    }
  • 相关阅读:
    7、【Linux系统编程】阻塞和非阻塞
    css样式
    如果目录不存在就创建
    api图片传输,转成64位字符串进行传输
    c#获取远程图片的方法
    分页
    使用微信js接口的方法 ,以调用相机为例
    某个文件下下面的文件批量改名
    查找本地文件中的特定字符串并替换代码
    第35月第6天 自定义view初始化
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11381625.html
Copyright © 2011-2022 走看看