https://www.luogu.org/problem/P3373
题目描述

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

1.将某区间每一个数乘上x

2.将某区间每一个数加上x

3.求出某区间每一个数的和
输入格式

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

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

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

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

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

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

输出包含若干行整数,即为所有操作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

说明/提示

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强_

样例说明:

故输出应为17、2(40 mod 38=2)
思路:维护两个标记:一个加法标记,一个乘法标记。记得修改乘法标记的时候要同时修改加法标记。

#include<iostream>
#include<cstdio>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn=1e5+5;
struct node
{ll l,r;ll sum;ll lazy1,lazy2;  //lazy标记
};node tree[maxn<<2];
ll a[maxn];
ll n,m,p;inline void mod(ll i)
{tree[i].lazy1%=p;tree[i].lazy2%=p;tree[i].sum%=p;
}void build(ll i,ll l,ll r)
{tree[i].l=l,tree[i].r=r;tree[i].lazy1=0,tree[i].lazy2=1;if(l==r){tree[i].sum=a[l];return ;}ll mid=(l+r)>>1;build(i<<1,l,mid); //左子树build(i<<1|1,mid+1,r);  //右子树tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;//区间和mod(i);
}void down1(ll i)//节点i的标记下传
{tree[i<<1].lazy1+=tree[i].lazy1;   //lazy标记下传tree[i<<1|1].lazy1+=tree[i].lazy1;tree[i<<1].sum+=tree[i].lazy1*(tree[i<<1].r-tree[i<<1].l+1);//修改值tree[i<<1|1].sum+=tree[i].lazy1*(tree[i<<1|1].r-tree[i<<1|1].l+1);mod(i<<1),mod(i<<1|1);tree[i].lazy1=0;
}void down2(ll i)//乘法标记
{tree[i<<1].lazy2*=tree[i].lazy2;tree[i<<1|1].lazy2*=tree[i].lazy2;tree[i<<1].lazy1*=tree[i].lazy2;tree[i<<1|1].lazy1*=tree[i].lazy2;tree[i<<1].sum*=tree[i].lazy2;tree[i<<1|1].sum*=tree[i].lazy2;mod(i<<1),mod(i<<1|1);tree[i].lazy2=1;
}void update1(ll i,ll l,ll r,ll v)
{if(tree[i].l==l&&tree[i].r==r)//要修改的区间就是当前区间{tree[i].sum+=(tree[i].r-tree[i].l+1)*v;//修改区间值tree[i].lazy1+=v;  //修改lazy标记mod(i);return ;}if(tree[i].lazy2!=1)down2(i);if(tree[i].lazy1)//走到这一步说明要用到子节点了 lazy下传down1(i);ll mid=(tree[i].l+tree[i].r)>>1;if(r<=mid)//左半区间update1(i<<1,l,r,v);else if(l>=mid+1)//右半区间update1(i<<1|1,l,r,v);else //左右均有{update1(i<<1,l,mid,v);update1(i<<1|1,mid+1,r,v);}tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;mod(i);
}void update2(ll i,ll l,ll r,ll v)
{if(tree[i].l==l&&tree[i].r==r)//要修改的区间就是当前区间{tree[i].sum*=v;//修改区间值tree[i].lazy2*=v; //修改lazy标记tree[i].lazy1*=v;mod(i);return ;}if(tree[i].lazy2!=1)down2(i);if(tree[i].lazy1)//走到这一步说明要用到子节点了 lazy下传down1(i);ll mid=(tree[i].l+tree[i].r)>>1;if(r<=mid)//左半区间update2(i<<1,l,r,v);else if(l>=mid+1)//右半区间update2(i<<1|1,l,r,v);else //左右均有{update2(i<<1,l,mid,v);update2(i<<1|1,mid+1,r,v);}tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;mod(i);
}ll query(ll i,ll l,ll r)
{if(tree[i].l==l&&tree[i].r==r)//要查询的区间就是当前区间return tree[i].sum;if(tree[i].lazy2!=1)//要用到子节点 lazy下传down2(i);if(tree[i].lazy1)down1(i);ll mid=(tree[i].l+tree[i].r)>>1;if(r<=mid)//左半部分return query(i<<1,l,r);else if(l>=mid+1)  //右半部分return query(i<<1|1,l,r);else //左右均有return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}int main()
{scanf("%lld %lld %lld",&n,&m,&p);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);build(1,1,n);int op;ll t1,t2,t3;for(ll i=0;i<m;i++){scanf("%d",&op);if(op==3){scanf("%lld%lld",&t1,&t2);printf("%lld\n",query(1,t1,t2)%p);}else if(op==1){scanf("%lld%lld%lld",&t1,&t2,&t3);update2(1,t1,t2,t3);}else{scanf("%lld%lld%lld",&t1,&t2,&t3);update1(1,t1,t2,t3);}}return 0;
}

洛谷 P3373 【模板】线段树 2相关推荐

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

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

  2. 专题·树链剖分【including 洛谷·【模板】树链剖分

    初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...

  3. 洛谷 - P1198 - 最大数 - 线段树

    https://www.luogu.org/problemnew/show/P1198 要问区间最大值,肯定是要用线段树的,不能用树状数组.(因为没有逆元?但是题目求的是最后一段,可以改成类似前缀和啊 ...

  4. 【洛谷 3372】线段树 1

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

  5. 洛谷P3352 [ZJOI2016]线段树

    P3352 [ZJOI2016]线段树 (^ w ^) 题目描述 小Yuuka遇到了一个题目:有一个序列a_1,a_2,?,a_n,q次操作,每次把一个区间内的数改成区间内的最大值,问最后每个数是多少 ...

  6. 【洛谷】【线段树】P3353 在你窗外闪耀的星星

    [题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...

  7. 洛谷 P3373 【模板】线段树 2 题解

    洛谷 P3373 [模板]线段树 2 题解 题面 题目链接:[戳这里](https://www.luogu.org/problemnew/show/P3373) 题目描述 输入输出格式 输入输出样例 ...

  8. 洛谷P3373线段树

    洛谷P3373 线段树模板题,主要对懒标的处理要求比较高. 有三种操作: 区间加法 区间乘法 区间求和查询 tips:我们对一个区间进行乘k操作的时候,他之前可能存在加法lazy还没pushdown, ...

  9. 洛谷 P3373 线段树2

    洛谷 P3373 线段树2 mul和pls更新某区间左右子树sum的时候,别忘了回头更新这个区间的sum 只有在传递给子序列之后,父序列的lz标记才能清零.其他时候,lz标记只增不减 #include ...

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

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

最新文章

  1. 8.11. Migrating MySQL Data into Elasticsearch using logstash
  2. 解决Android emulator PANIC: Missing emulator engine program for ‘x86‘ CPU.
  3. CEO 赠书 | 甲之蜜糖乙之砒霜,创新者也将成为守旧者
  4. Maven项目中获取classpath和资源文件的路径
  5. kong 使用jwt RSA256证书
  6. Java生鲜电商平台-订单配送模块的架构与设计
  7. Jsp+Servlet+Mysql实现的在线图书商城源码
  8. 两个网口芯片接一个变压器_关于以太网网络变压器的几个问题
  9. 区块链技术指南之分布式的一致性
  10. python九九乘法表代码
  11. the system requirements are not satisied或Android Studio不支持HAXM
  12. CH2-Java编程基础(7个案例实现)
  13. java 调用ffmpeg 转成mp4_Java+Windows+ffmpeg实现视频转换
  14. BiliDuang(哔哩哔哩视频下载器)
  15. 小程序canvas画入圆形图片
  16. 特殊的Excel填充序号技巧,总有一种你会遇到【特别实用,赶紧收藏】
  17. 绿荫工作室爱选修app内测
  18. Ironic 裸金属管理服务
  19. python 合并word文件_python读取word合并单元格
  20. android activity获取dialog对象,Android开发笔记之:Dialog的使用详解

热门文章

  1. 蓝桥杯——测试次数·摔手机(2018JavaB组第4题,17分)
  2. python的socket
  3. 【odroid-xu3】 ODROID-XU3软件环境搭建记录
  4. 代写演讲稿的写作要求有哪些
  5. 判断一个点是否在矩形内PtInRegion-解决PtInRect不能正确判断不同形式TRent的情况
  6. 干货!最全的AI速查表|神经网络,机器学习,深度学习
  7. 努比亚服务器设置在哪个文件夹,【小师傅教程】关于 努比亚自带邮箱 设置
  8. montypython买火柴_python nltk 笔记(持续更新)
  9. MySQL中什么是码_数据库中的码是什么含义?
  10. Wifi_认证 、关联 和 四次握手(WPA/WPA2)