洛谷 P3373 【模板】线段树 2 题解
P3373 【模板】线段树 2
题目描述
如题,已知一个数列,你需要进行下面三种操作:
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)
【思路】
线段树
大部分的地方是和线段树1这道题一样的
我只在这里说一下不同的地方
【取模】
在每一次有加法或者有乘法
涉及到运算的地方能模的都模一下就好了
【乘法和加法】
原来线段树1模板里面有一个lazy
那是因为有加法这种运算
现在有加法和乘法这两种运算
那就开两个类似lazy的东西储存就好了
【lazy标记的修改】
在修改加法lazy标记的时候就正常修改就好了
但是修改乘法的时候就不行了
因为前面可能有加过的数
所以还要连带着一起修改一下加法的lazy标记
因为入过前面加过某个数
那现在就是
(a + b)
这个时候如果乘上一个数c
(a +b) * c = ac + bc
a乘了c,加法的lazy标记也乘了c所以要修改加法的标记
【完整代码】
#include<iostream>
#include<cstdio>
#define int long long
#define lson (k << 1)
#define rson (k << 1 | 1)
using namespace std;
const int Max = 100005;
int read()
{
int sum = 0,fg = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-')fg = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
sum = sum * 10 + c - '0';
c = getchar();
}
return sum * fg;
}
int n,m,p;
int opl,opr,opx;
int ans;
struct node
{
int l,r;
int sum;
int cheng,jia;
}a[Max << 2];
void build(int k,int l,int r)
{
a[k].cheng = 1;
a[k].jia = 0;
a[k].l = l,a[k].r = r;
if(l == r)
{
a[k].sum = read();
a[k].sum %= p;
return;
}
int mid = (l + r) >> 1;
build(lson,l,mid);
build(rson,mid + 1,r);
a[k].sum = a[lson].sum + a[rson].sum;
a[k].sum %= p;
}
void down(int k)
{
if(a[k].jia != 0 || a[k].cheng != 1)
{
a[rson].cheng = (a[rson].cheng * a[k].cheng) % p;
a[lson].cheng = (a[lson].cheng * a[k].cheng) % p;
a[rson].jia = (a[rson].jia * a[k].cheng + a[k].jia) % p;
a[lson].jia = (a[lson].jia * a[k].cheng + a[k].jia) % p;
a[rson].sum = (a[rson].sum * a[k].cheng % p + a[k].jia * (a[rson].r - a[rson].l + 1)) % p;
a[lson].sum = (a[lson].sum * a[k].cheng % p + a[k].jia * (a[lson].r - a[lson].l + 1)) % p;
a[k].cheng = 1;
a[k].jia = 0;
}
}
void change1(int k)
{
if(opl <= a[k].l && opr >= a[k].r)
{
a[k].cheng = (a[k].cheng * opx) % p;
a[k].jia = (a[k].jia * opx) % p;
a[k].sum = (a[k].sum * opx) % p;
return;
}
down(k);
int mid = (a[k].l + a[k].r) >> 1;
if(opl <= mid)change1(lson);
if(opr > mid)change1(rson);
a[k].sum = (a[lson].sum + a[rson].sum) % p;
}
void change2(int k)
{
if(opl <= a[k].l && opr >= a[k].r)
{
a[k].jia = (a[k].jia + opx) % p;
a[k].sum = (a[k].sum + (a[k].r - a[k].l + 1) * opx % p) % p;
return;
}
down(k);
int mid = (a[k].l + a[k].r) >> 1;
if(opl <= mid)change2(lson);
if(opr > mid)change2(rson);
a[k].sum = (a[lson].sum + a[rson].sum) % p;
}
void query(int k)
{
if(opl <= a[k].l && opr >= a[k].r)
{
ans += a[k].sum;
ans %= p;
return;
}
down(k);
int mid = (a[k].l + a[k].r) >> 1;
if(opl <= mid)query(lson);
if(opr > mid)query(rson);
}
signed main()
{
n = read(),m = read(),p = read();
build(1,1,n);
for(register int i = 1;i <= m;++ i)
{
int qwq = read();
if(qwq == 1)
{
opl = read(),opr = read(),opx = read();
change1(1);
}
else
if(qwq == 2)
{
opl = read(),opr = read(),opx = read();
change2(1);
}
else
{
opl = read(),opr = read();
ans = 0;
query(1);
cout << ans % p << endl;
}
}
return 0;
}
洛谷 P3373 【模板】线段树 2 题解的更多相关文章
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 线段树_区间加乘(洛谷P3373模板)
题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字 ...
- 洛谷 P2391 白雪皑皑 线段树+优化
题目描述: 现在有 \(N\) 片雪花排成一列. Pty 要对雪花进行$ M $次染色操作,第 \(i\)次染色操作中,把\((i*p+q)%N+1\) 片雪花和第\((i*q+p)%N+1\)片雪花 ...
- 洛谷P5280 [ZJOI2019]线段树
https://www.luogu.org/problemnew/show/P5280 省选的时候后一半时间开这题,想了接近两个小时的各种假做法,之后想的做法已经接近正解了,但是有一些细节问题理不 ...
- 洛谷 - P1198 - 最大数 - 线段树
https://www.luogu.org/problemnew/show/P1198 要问区间最大值,肯定是要用线段树的,不能用树状数组.(因为没有逆元?但是题目求的是最后一段,可以改成类似前缀和啊 ...
- 【洛谷】【线段树】P1471 方差
[题目背景:] 滚粗了的HansBug在收拾旧数学书,然而他发现了什么奇妙的东西. [题目描述:] 蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数.他想算算这个数列的平均数和方差 ...
- 【洛谷】【线段树】P1047 校门外的树
[题目描述:] 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L ...
- 【洛谷】【线段树】P1886 滑动窗口
[题目描述:] 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. [输入格式:] 输入一共 ...
- 【洛谷】【线段树】P3353 在你窗外闪耀的星星
[题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...
- 洛谷P3374(线段树)(询问区间和,支持单点修改)
洛谷P3374 //询问区间和,支持单点修改 #include <cstdio> using namespace std; ; struct treetype { int l,r,sum; ...
随机推荐
- HTTP之缓存命中
缓存命中和缓存未命中 ========================摘自<HTTP权威指南>============================== 1.缓存命中和缓存未命中 可以用 ...
- python之函数filter、reduce
---恢复内容开始--- 一.filter函数 filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表. 该接收两个参数,第一个为函数,第二个为序列,对序列中每个元 ...
- yarn安装node-sass失败问题
注:使用 yarn install 命令安装依赖时报错 第一步:更改镜像源 yarn config set registry https://registry.npm.taobao.org -g 第二 ...
- Hash冲突的解决--暴雪的Hash算法
Hash冲突的解决--暴雪的Hash算法https://usench.iteye.com/blog/2199399https://www.bbsmax.com/A/kPzOO7a8zx/
- MySQL中的 redo 日志文件
MySQL中的 redo 日志文件 MySQL中有三种日志文件,redo log.bin log.undo log.redo log 是 存储引擎层(innodb)生成的日志,主要为了保证数据的可靠性 ...
- Prometheus 监控Docker服务器及Granfanna可视化
Prometheus 监控Docker服务器及Granfanna可视化 cAdvisor(Container Advisor)用于收集正在运行的容器资源使用和性能信息. 使用Prometheus监控c ...
- windows配置flutter的注意点
参考官网配置:https://flutter.cn/docs/get-started/install/windows 注意点: 1. 配置好环境变量后,必须重启电脑才有效果(后面还有需要重启的,所以到 ...
- office2016下载安装
https://jingyan.baidu.com/article/359911f5acfa4357fe030631.html
- AI:WEB:1 Walkthrough
AI: Web: 1 Vulnhub Walkthrough靶机下载:https://www.vulnhub.com/entry/ai-web-1,353/测试方法: Nmap网络扫描 浏 ...
- mysql后台线程详解
1.mysql后台线程 mysql后台线程主要用于维持服务器的正常运行和完成用户提交的任务,主要包括:master thread,read thread,write thread,redo log t ...