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

将某区间每一个数乘上 xx

将某区间每一个数加上 xx

求出某区间每一个数的和

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

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

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

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

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

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

输出格式
输出包含若干行整数,即为所有操作 33 的结果。
思路:虽然多了一个区间乘法,但是还是蛮难做的。今天才发现我一开始学线段树的时候做过这道题目,但是在后面的比赛训练种,并没有接触过区间乘法的题目,就给忘的一干二净,写篇博客记录一下。
需要额外注意的地方:
①在pushdown的过程中,我们在计算左右子树和的时候,采用乘法优先的原则,即规定好segtree[root* 2].value=(segtree[root* 2].value* segtree[root].mul+segtree[root].add*(本区间长度))%p。而不是加法优先的原则。
②在对区间进行加一个数的时候,没有额外需要注意的;但是当区间乘以一个数的时候,这个区间之前加的值,也需要额外的乘以这个数字。
具体解释看代码:
这个代码完全可以当作模板了^ _ ^

#include<bits/stdc++.h>
#define ll long long
using namespace std;const int maxx=1e5+100;
struct node{int l,r;ll sum,lazyx,lazyj;
}p[maxx<<2];
int n,m,q;
ll a[maxx];inline void pushup(int cur)
{p[cur].sum=(p[cur<<1].sum+p[cur<<1|1].sum)%q;
}
inline void pushdown(int cur)
{p[cur<<1].sum=(p[cur<<1].sum*p[cur].lazyx+(ll)(p[cur<<1].r-p[cur<<1].l+1)*p[cur].lazyj)%q;p[cur<<1|1].sum=(p[cur<<1|1].sum*p[cur].lazyx+(ll)(p[cur<<1|1].r-p[cur<<1|1].l+1)*p[cur].lazyj)%q;//子节点的和=子节点的和乘以父节点的乘法懒惰标记+父节点的加法懒惰标记*当前区间的长度p[cur<<1].lazyj=(p[cur<<1].lazyj*p[cur].lazyx+p[cur].lazyj)%q;p[cur<<1|1].lazyj=(p[cur<<1|1].lazyj*p[cur].lazyx+p[cur].lazyj)%q;//加法的懒惰标记需要乘以父节点的乘法懒惰标记再加上父节点的加法懒惰标记p[cur<<1].lazyx=(p[cur<<1].lazyx*p[cur].lazyx)%q;p[cur<<1|1].lazyx=(p[cur<<1|1].lazyx*p[cur].lazyx)%q;p[cur].lazyj=0;p[cur].lazyx=1;
}
inline void build(int l,int r,int cur)
{p[cur].l=l;p[cur].r=r;p[cur].lazyj=0;p[cur].lazyx=1;if(l==r){p[cur].sum=(a[l])%q;return ;}int mid=l+r>>1;build(l,mid,cur<<1);build(mid+1,r,cur<<1|1);pushup(cur);
}
inline void updatej(int l,int r,int cur,ll x)//更新加法
{int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){p[cur].lazyj+=x;p[cur].lazyj%=q;p[cur].sum+=(ll)(p[cur].r-p[cur].l+1)*x;p[cur].sum%=q;return ;}pushdown(cur);int mid=L+R>>1;if(r<=mid) updatej(l,r,cur<<1,x);else if(l>mid) updatej(l,r,cur<<1|1,x);else updatej(l,mid,cur<<1,x),updatej(mid+1,r,cur<<1|1,x);pushup(cur);
}
inline void updatex(int l,int r,int cur,ll x)//更新乘法
{int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){p[cur].sum=(p[cur].sum*x)%q;p[cur].lazyx=(p[cur].lazyx*x)%q;p[cur].lazyj=(p[cur].lazyj*x)%q;return ;}pushdown(cur);int mid=L+R>>1;if(r<=mid) updatex(l,r,cur<<1,x);else if(l>mid) updatex(l,r,cur<<1|1,x);else updatex(l,mid,cur<<1,x),updatex(mid+1,r,cur<<1|1,x);pushup(cur);
}
inline ll query(int l,int r,int cur)//求和
{int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r) return p[cur].sum%q;pushdown(cur);int mid=L+R>>1;if(r<=mid) return query(l,r,cur<<1)%q;else if(l>mid) return query(l,r,cur<<1|1)%q;else return (query(l,mid,cur<<1)%q+query(mid+1,r,cur<<1|1)%q)%q;
}
int main()
{while(~scanf("%d%d%d",&n,&m,&q)){for(int i=1;i<=n;i++) scanf("%lld",&a[i]);build(1,n,1);int x,y,z;ll k;while(m--){scanf("%d",&x);if(x==1){scanf("%d%d%lld",&y,&z,&k);updatex(y,z,1,k);}else if(x==2){scanf("%d%d%lld",&y,&z,&k);updatej(y,z,1,k);}else{scanf("%d%d",&y,&z);printf("%lld\n",query(y,z,1)%q);} }}return 0;
}

努力加油a啊

P3373 【模板】线段树 2(区间乘法+区间加法+区间求和)相关推荐

  1. 线段树线段树的创建线段树的查询单节点更新区间更新

    目录 线段树 什么是线段树? 线段树的创建 线段树的查询 单节点更新 区间更新 未完待续 线段树 实现问题:常用于求数组区间最小值 时间复杂度:(1).建树复杂度:nlogn.(2).线段树算法复杂度 ...

  2. hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询

    点权树的模板题,另外发现树状数组也是可以区间更新的.. 注意在对链进行操作时方向不要搞错 线段树版本 #include<bits/stdc++.h> using namespace std ...

  3. 洛谷(P3373)线段树加乘混合模板

    题目链接:P3373 [模板]线段树 2 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 这道题目的意思很明确,就是要我们在线完成区间的乘和加运算并支持查询区间和的一个问题.处理这道 ...

  4. 洛谷P3373 线段树2(乘法加法lazytag)

    线段树模板题,含lazytag的线段树码量本身就比较大,再加入乘法标记,还要考虑先乘后加的问题,本蒟蒻一调就是几个小时. P3373 [模板]线段树 2https://www.luogu.com.cn ...

  5. 【线段树】HDU 3397 Sequence operation 区间合并

    操作 Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters i ...

  6. 线段树优化建图详解——区间连边之技巧,吊打紫题之利器

    我们从一道例题开始. CF786B Description Solution 朴素解法: 暴力连边+最短路 对于每次连边操作,我们逐一连边,最后在图上跑一遍单源最短路径算法即可. 时间复杂度 O ( ...

  7. 洛谷 p3372 模板-线段树 1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个 ...

  8. ACM模板——线段树树状数组ST表

    int bit[maxn],n; void init() {n = maxn;memset(bit,0,sizeof(bit)); } int sum(int i) {int s = 0;while( ...

  9. 【2019牛客暑期多校训练营(第二场)- E】MAZE(线段树优化dp,dp转矩阵乘法,线段树维护矩阵乘法)

    题干: 链接:https://ac.nowcoder.com/acm/contest/882/E?&headNav=acm 来源:牛客网 Given a maze with N rows an ...

  10. 算法模板——线段树6(二维线段树:区域加法+区域求和)(求助phile)

    实现功能--对于一个N×M的方格,1:输入一个区域,将此区域全部值作加法:2:输入一个区域,求此区域全部值的和 其实和一维线段树同理,只是不知道为什么速度比想象的慢那么多,求解释...@acphile ...

最新文章

  1. Nokia是否还有未来 - 小议诺基亚和微软的战略布局
  2. 【Java基础】重写与重载
  3. Beyond Compare 3 许可证密钥被撤销
  4. ubuntu运行Faster R-CNN
  5. C语言程序设计 函数递归调用示例
  6. Spark SQL(三)之视图与执行SQL
  7. 《你的灯亮着吗》 读书笔记三
  8. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_07-vuejs研究-vuejs基础-v-bind指令...
  9. 【情感识别】基于matlab GUI SVM语音情感识别【含Matlab源码 869期】
  10. 软件开发系统类别记录
  11. 逆波兰表达式(含小数)、C语言
  12. redux 的入门级别使用 讲解
  13. 服务器appcrash的问题怎么修复,Win7系统出现APPCRASH错误的修复方法
  14. 怎么查看笔记本内存条型号_怎么看电脑内存条型号 电脑内存条型号查看方法【详解】...
  15. R语言和RStudio开发环境的下载与安装
  16. Java基础(五):Java数组声明与初始化
  17. 信息量、熵、交叉熵、KL散度、JS散度、Wasserstein距离
  18. 38个PS常用工具箱快捷键,找工具不慌、不忙、不乱(纯干货)
  19. 影视级调色lut预设包 Triune Color Cinematic LUTs V2
  20. 美国百万智能摄像头背后的中国云技术

热门文章

  1. C#中如何创建文件夹
  2. 已知序列求蝶形运算_(数字信号处理选择题.doc
  3. 外观模式和代理模式的联系和区别_java23种设计模式-结构型模式之外观模式
  4. burpsuite下载使用详讲
  5. 如何用git上传文件
  6. nginx输出日志_ingressnginx持久化日志
  7. springboot调用python脚本_Springboot实现上传文件接口,使用python的requests进行组装报文上传文件的方法...
  8. WebView无法自动播放h5的video视频标签解决办法
  9. opencv 阈值分割_CVPR2019实例分割Mask Scoring RCNN
  10. 最详细的linux下的磁盘分区及格式化