题目描述
如题,已知一个数列,你需要进行下面三种操作:

将某区间每一个数乘上 x

将某区间每一个数加上 x

求出某区间每一个数的和

输入格式
第一行包含三个整数 n,m,p,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 n 个用空格分隔的整数,其中第 ii 个数字表示数列第 i 项的初始值。

接下来 m 行每行包含若干个整数,表示一个操作,具体如下:

操作 1: 格式:1 x y k 含义:将区间 [x,y] 内每个数乘上 kk

操作 2: 格式:2 x y k 含义:将区间 [x,y] 内每个数加上 kk

操作 3: 格式:3 x y 含义:输出区间[x,y] 内每个数的和对 pp 取模所得的结果

输出格式
输出包含若干行整数,即为所有操作 3 的结果。

题解:

线段树模板题
通过此题可以充分诠释pushdown的用法、

//核心代码,维护lazytag
void pushdown(int root, int l, int r){
   
    int m=(l+r)/2;
//根据我们规定的优先度,儿子的值=此刻儿子的值*爸爸的乘法lazytag+儿子的区间长度*爸爸的加法lazytag
    st[root*2].v=(st[root*2].v*st[root].mul+st[root].add*(m-l+1))%p;
    st[root*2+1].v=(st[root*2+1].v*st[root].mul+st[root].add*(r-m))%p;
//很好维护的lazytag
    st[root*2].mul=(st[root*2].mul*st[root].mul)%p;
    st[root*2+1].mul=(st[root*2+1].mul*st[root].mul)%p;
    st[root*2].add=(st[root*2].add*st[root].mul+st[root].add)%p;
    st[root*2+1].add=(st[root*2+1].add*st[root].mul+st[root].add)%p;
//把父节点的值初始化
    st[root].mul=1;
    st[root].add=0;
    return ;
}

建议代码直接背过。。。
详细过程看洛谷题解

代码

#include <iostream>
#include <cstdio>
using namespace std;
//题目中给的p
int p;
//暂存数列的数组
long long a[100007];
//线段树结构体,v表示此时的答案,mul表示乘法意义上的lazytag,add是加法意义上的
struct node{
   
    long long v, mul, add;
}st[400007];
//buildtree
void buildtree(int root, int l, int r){
   
//初始化lazytag
    st[root].mul=1;
    st[root].add=0;
    if(l==r){
   
        st[root].v=a[l];
    }
    else{
   
        int m=(l+r)/2;
        buildtree(root*2, l, m);
        buildtree(root*2+1, m+1, r);
        st[root].v=st[root*2].v+st[root*2+1].v;
    }
    st[root].v%=p;
    return ;
}
//核心代码,维护lazytag
void pushdown(int root, int l, int r){
   
    int m=(l+r)/2;
//根据我们规定的优先度,儿子的值=此刻儿子的值*爸爸的乘法lazytag+儿子的区间长度*爸爸的加法lazytag
    st[root*2].v=(st[root*2].v*st[root].mul+st[root].add*(m-l+1))%p;
    st[root*2+1].v=(st[root*2+1].v*st[root].mul+st[root].add*(r-m))%p;
//很好维护的lazytag
    st[root*2].mul=(st[root*2].mul*st[root].mul)%p;
    st[root*2+1].mul=(st[root*2+1].mul*st[root].mul)%p;
    st[root*2].add=(st[root*2].add*st[root].mul+st[root].add)%p;
    st[root*2+1].add=(st[root*2+1].add*st[root].mul+st[root].add)%p;
//把父节点的值初始化
    st[root].mul=1;
    st[root].add=0;
    return ;
}
//update1,乘法,stdl此刻区间的左边,stdr此刻区间的右边,l给出的左边,r给出的右边
void update1(int root, int stdl, int stdr, int l, int r, long long k){
   
//假如本区间和给出的区间没有交集
    if(r<stdl || stdr<l){
   
        return ;
    }
//假如给出的区间包含本区间
    if(l<=stdl && stdr<=r){
   
        st[root].v=(st[root].v*k)%p;
        st[root].mul=(st[root].mul*k)%p;
        st[root].add=(st[root].add*k)%p;
        return ;
    }
//假如给出的区间和本区间有交集,但是也有不交叉的部分
//先传递lazytag
    pushdown(root, stdl, stdr);
    int m=(stdl+stdr)/2;
    update1(root*2, stdl, m, l, r, k);
    update1(root*2+1, m+1, stdr, l, r, k);
    st[root].v=(st[root*2].v+st[root*2+1].v)%p;
    return ;
}
//update2,加法,和乘法同理
void update2(int root, int stdl, int stdr, int l, int r, long long k){
   
    if(r<stdl || stdr<l){
   
        return ;
    }
    if(l<=stdl && stdr<=r){
   
        st[root].add=(st[root].add+k)%p;
        st[root].v=(st[root].v+k*(stdr-stdl+1))%p;
        return ;
    }
    pushdown(root, stdl, stdr);
    int m=(stdl+stdr)/2;
    update2(root*2, stdl, m, l, r, k);
    update2(root*2+1, m+1, stdr, l, r, k);
    st[root].v=(st[root*2].v+st[root*2+1].v)%p;
    return ;
}
//访问,和update一样
long long query(int root, int stdl, int stdr, int l, int r){
   
    if(r<stdl || stdr<l){
   
        return 0;
    }
    if(l<=stdl && stdr<=r){
   
        return st[root].v;
    }
    pushdown(root, stdl, stdr);
    int m=(stdl+stdr)/2;
    return (query(root*2, stdl, m, l, r)+query(root*2+1, m+1, stdr, l, r))%p;
}
int main(){
   
    int n, m;
    scanf("%d%d%d", &n, &m, &p);
    for(int i=1; i<=n; i++){
   
        scanf("%lld", &a[i]);
    }
    buildtree(1, 1, n);
    while(m--){
   
        int chk;
        scanf("%d", &chk);
        int x, y;
        long long k;
        if(chk==1){
   
            scanf("%d%d%lld", &x, &y, &k);
            update1(1, 1, n, x, y, k);
        }
        else if(chk==2){
   
            scanf("%d%d%lld", &x, &y, &k);
            update2(1, 1, n, x, y, k);
        }
        else{
   
            scanf("%d%d", &x, &y);
            printf("%lld\n", query(1, 1, n, x, y));
        }
    }
    return 0;
}