先乘后加,懒标记更好维护(线段树)

P3373 【模板】线段树 2

当乘法和加法标记同时存在时,pushdown中传递懒标记时,先传乘标记,后传加标记更好维护  
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int const N=1e5+7;
ll n,m,mod;
ll a[N];
ll tree[N<<2];
struct L{
    ll a,b;  //a是*标记,b是+标记    //a为子树待加的数,b为子树待乘的数
    void _mod(int mod){
        a%=mod;b%=mod;
    }
}ly[N<<2];
void bulid(int p,int l,int r){
    ly[p].a =1;
    if(l==r){ tree[p]=a[l]%mod;return ;}
    int mid=(l+r)>>1;
    bulid(p*2,l,mid);
    bulid(p*2+1,mid+1,r);
    tree[p]=(tree[p*2]%mod+tree[p*2+1]%mod)%mod;
}
void pushdown(int p,int len){
    tree[p*2]=(tree[p*2]*ly[p].a%mod +(ly[p].b *(len-len/2)%mod))%mod;
    tree[p*2+1]=(tree[p*2+1]*ly[p].a%mod +(ly[p].b *(len/2))%mod)%mod;
    ly[p*2].a =(ly[p*2].a%mod *ly[p].a%mod)%mod ;        
    ly[p*2+1].a =(ly[p*2+1].a%mod *ly[p].a%mod)%mod ;    //以后可以用mu表示*标记
    ly[p*2].b =(ly[p*2].b*ly[p].a%mod  + ly[p].b%mod)%mod ;       //重点
    ly[p*2+1].b =(ly[p*2+1].b*ly[p].a%mod  + ly[p].b%mod)%mod ;    //
    ly[p].a =1;ly[p].b =0;
}
void change1(int p,int l,int r,int x,int y,int k){   //乘法维护
    if(x<=l&&r<=y){
        tree[p]=(tree[p]%mod * k%mod)%mod;
        ly[p].b=(ly[p].b%mod*k%mod)%mod;   //原先待加的数要乘上新来的乘数k
        ly[p].a=(ly[p].a%mod*k%mod)%mod;
        return ;
    }
    if(ly[p].a!=1 || ly[p].b ) pushdown(p,r-l+1);
    int mid=(l+r) >> 1;
    if(x<=mid) change1(p*2,l,mid,x,y,k);
    if(y>=mid+1) change1(p*2+1,mid+1,r,x,y,k);
    tree[p]=(tree[p*2]%mod+tree[p*2+1]%mod)%mod;
}
void change2(int p,int l,int r,int x,int y,int k){   //加法维护
    if(x<=l&&r<=y){
        tree[p]=(tree[p]%mod+(r-l+1)*k%mod)%mod;
        ly[p].b =(ly[p].b%mod +k%mod)%mod;
        return ;
    }
    if(ly[p].a!=1 || ly[p].b ) pushdown(p,r-l+1);
    int mid=(l+r) >> 1;
    if(x<=mid) change2(p*2,l,mid,x,y,k);
    if(mid+1<=y) change2(p*2+1,mid+1,r,x,y,k);
    tree[p]=(tree[p*2]%mod+tree[p*2+1]%mod)%mod;
}
ll ask(int p,int l,int r,int x,int y){  //询问区间和,所以不用改tree 
    if(x<=l&&r<=y){    return tree[p]%=mod;    }
    if(ly[p].a!=1 || ly[p].b ) pushdown(p,r-l+1); 
    int mid=(l+r) >> 1;
    ll res=0;
    if(x<=mid) res=(res%mod+ask(p*2,l,mid,x,y)%mod)%mod;
    if(mid+1<=y) res=(res%mod+ask(p*2+1,mid+1,r,x,y)%mod)%mod;
    return res%=mod;
}
int main(){
    cin >> n >> m >> mod;
    for(int i=1;i<=n;++i){
        cin >> a[i];
    }
    bulid(1,1,n);
    while(m--){
        int op,x,y,k;
        cin >> op >> x >> y;
        if(op==1){
            cin >> k;
            change1(1,1,n,x,y,k);
        }
        else if(op==2){
            cin >> k;
            change2(1,1,n,x,y,k);
        }
        else{
            cout << ask(1,1,n,x,y)%mod << "\n";  //cout << endl;输出一次endl就要清空缓存,比较慢  //cout << "\n"快一点 
        }    
    }
    return 0; 
} 
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
正在热议
更多
# 春招至今,你的战绩如何? #
11086次浏览 95人参与
# 你的实习产出是真实的还是包装的? #
1960次浏览 42人参与
# 巨人网络春招 #
11371次浏览 223人参与
# 军工所铁饭碗 vs 互联网高薪资,你会选谁 #
7643次浏览 43人参与
# 简历第一个项目做什么 #
31749次浏览 341人参与
# 重来一次,我还会选择这个专业吗 #
433551次浏览 3926人参与
# MiniMax求职进展汇总 #
24121次浏览 309人参与
# 当下环境,你会继续卷互联网,还是看其他行业机会 #
187211次浏览 1122人参与
# 牛客AI文生图 #
21447次浏览 238人参与
# 不考虑薪资和职业,你最想做什么工作呢? #
152456次浏览 888人参与
# 研究所笔面经互助 #
118967次浏览 577人参与
# 简历中的项目经历要怎么写? #
310370次浏览 4219人参与
# AI时代,哪些岗位最容易被淘汰 #
63836次浏览 828人参与
# 面试紧张时你会有什么表现? #
30513次浏览 188人参与
# 你今年的平均薪资是多少? #
213146次浏览 1039人参与
# 你怎么看待AI面试 #
180146次浏览 1258人参与
# 高学历就一定能找到好工作吗? #
64331次浏览 620人参与
# 你最满意的offer薪资是哪家公司? #
76546次浏览 374人参与
# 我的求职精神状态 #
448136次浏览 3129人参与
# 正在春招的你,也参与了去年秋招吗? #
363523次浏览 2638人参与
# 腾讯音乐求职进展汇总 #
160677次浏览 1112人参与
# 校招笔试 #
471210次浏览 2964人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务