[模板]线段树2 (区间乘 + 区间加 + 区间求和)

P3373 【模板】线段树 2

时间限制: 1.00s 内存限制: 125.00MB

复制 Markdown

中文

退出 IDE 模式

题目描述

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

  • 将某区间每一个数乘上 x;
  • 将某区间每一个数加上 x;
  • 求出某区间每一个数的和。

输入格式

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

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

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

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

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

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

输出格式

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

输入输出样例

输入 #1复制运行

复制代码
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

输出 #1复制运行

复制代码
17
2

说明/提示

【数据范围】

对于 30% 的数据:n≤8,q≤10。

对于 70% 的数据:n≤103,q≤104。

对于 100% 的数据:1≤n≤105,1≤q≤105,1≤ai​,k≤104。

除样例外,m=571373。

(数据已经过加强 ^_^)

样例说明:

故输出应为 17、2(40mod38=2)。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
long long a[N],n,m,mod;
struct SegmentTree{
    long long l,r;
    long long sum,add,mul;
    #define l(x) tree[x].l
    #define r(x) tree[x].r
    #define sum(x) tree[x].sum
    #define add(x) tree[x].add
    #define mul(x) tree[x].mul
}tree[4*N];
void build(int p,int l,int r){
    l(p)=l,r(p)=r,mul(p)=1;
    if(l==r){sum(p)=a[l]%mod;return;}
    int mid = (l+r)>>1;
    build(2*p,l,mid);
    build(2*p+1,mid+1,r);
    sum(p)=(sum(p*2)+sum(p*2+1))%mod;
}
void spread(int p){
        sum(p*2)=(sum(p*2)*mul(p)+add(p)*(r(p*2)-l(p*2)+1))%mod;     //更新左子节点信息
        sum(p*2+1)=(sum(p*2+1)*mul(p)+add(p)*(r(p*2+1)-l(p*2+1)+1))%mod;   //更新右子节点信息
        mul(p*2)=(mul(p*2)*mul(p))%mod;
        mul(p*2+1)=(mul(p*2+1)*mul(p))%mod;
        add(p*2)=(add(p*2)*mul(p)+add(p))%mod;   //左子节点加延迟标记
        add(p*2+1)=(add(p*2+1)*mul(p)+add(p))%mod; //右子节点加延迟标记
        add(p)=0;
        mul(p)=1;
}
void changemul(int p,int l,int r,int d){
    if(l<=l(p)&&r>=r(p)){   //完全覆盖
        sum(p)=sum(p)*d%mod;    //更新节点信息
        add(p)=add(p)*d%mod;      //延迟标记
        mul(p)=mul(p)*d%mod;
        return;
    }
    spread(p);
    int mid=(l(p)+r(p))>>1;
    if(l<=mid)changemul(p*2,l,r,d);
    if(r>mid)changemul(p*2+1,l,r,d);
    sum(p)=(sum(p*2)+sum(p*2+1))%mod;
}
void changeadd(int p,int l,int r,int d){
    if(l<=l(p)&&r>=r(p)){   //完全覆盖
        sum(p)=(sum(p)+1LL*d*(r(p)-l(p)+1))%mod;    //更新节点信息
        add(p)=(add(p)+d)%mod;      //延迟标记
        return;
    }
    spread(p);
    int mid=(l(p)+r(p))>>1;
    if(l<=mid)changeadd(p*2,l,r,d);
    if(r>mid)changeadd(p*2+1,l,r,d);
    sum(p)=(sum(p*2)+sum(p*2+1))%mod;
}
long long query(int p,int l,int r){
    if(l<=l(p)&&r>=r(p))return sum(p);
    spread(p);  //下传延迟标记
    int mid=(l(p)+r(p))>>1;
    long long val=0;
    if(l<=mid)val=(val+query(p*2,l,r))%mod;
    if(r>mid)val=(val+query(p*2+1,l,r))%mod;
    return val;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m>>mod;
    for(int i=1;i<=n;i++)cin>>a[i];
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int op;cin>>op;
        if(op==1){
            long long l,r,k;
            cin>>l>>r>>k;
            changemul(1,l,r,k);
        }else if (op==2){
            int l,r,k;
            cin>>l>>r>>k;
            changeadd(1,l,r,k);
        }else {
            int l,r;
            cin>>l>>r;
            cout<<query(1,l,r)%mod<<'\n';
        }
    }
    return 0;
}
相关推荐
Gorway2 小时前
解析残差网络 (ResNet)
算法
拖拉斯旋风3 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect3 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript
灵感__idea17 小时前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
Wect1 天前
LeetCode 130. 被围绕的区域:两种解法详解(BFS/DFS)
前端·算法·typescript
NAGNIP2 天前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
颜酱2 天前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub2 天前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉