更好的题目阅读效果
题目描述
如题,已知一个数列,你需要进行下面三种操作:
将某区间每一个数乘上 x
将某区间每一个数加上 x
求出某区间每一个数的和
输入格式
第一行包含三个整数 n,m,p,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含 nn个用空格分隔的整数,其中第 i个数字表示数列第 i 项的初始值。
接下来 m 行每行包含若干个整数,表示一个操作,具体如下:
操作 1: 格式:1 x y k 含义:将区间 [x,y]内每个数乘上 k
操作 2: 格式:2 x y k 含义:将区间 [x,y]内每个数加上 k
操作 3: 格式:3 x y 含义:输出区间 [x,y]内每个数的和对 p 取模所得的结果
输出格式
输出包含若干行整数,即为所有操作 3 的结果。
输入输出样例
输入
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
输出
17
2
说明/提示
【数据范围】
对于30%的数据:n≤8,m≤10
对于70%的数据: n≤10^3 ,m≤10^4
对于100%的数据: n≤10^5 ,m≤10^5
思路:
首先看到这道题,我们想到的是用lazy标记来完成这道题。
可是它有乘法,怎么办呢?
我们不妨设两个lazy,一个用来存加法,一个存乘法
down:
这时讲到我们的核心部分:down(向下传递)
我们一般的down只有加法,这次多了乘法
我们规定乘法优先:
a[k*2].flag2=(a[k*2].flag2*a[k].flag2)%p;
a[k*2+1].flag2=(a[k*2+1].flag2*a[k].flag2)%p;
后面再算加法:
a[k*2].flag1=(a[k*2].flag1*a[k].flag2+a[k].flag1)%p;
//乘法递增加法,在下面我会讲的(章节:加和乘修改——乘)
a[k*2+1].flag1=(a[k*2+1].flag1*a[k].flag2+a[k].flag1)%p;
最后初始化
a[k].flag1=0;
a[k].flag2=1;
这时,问题来了:我们怎么计算它更改后的数值呢?
可以分成两部分:
儿子的值乘父亲的lazy乘法标记的值
原因:应为是区间乘法,所以就乘
儿子的区间长度乘父亲lazy加法标记
原因:和普通线段树加法同理
把两个合起来就行了:
a[k*2].w=(a[k*2].w*a[k].flag2+(a[k*2].r-a[k*2].l+1)*a[k].flag1)%p;
a[k*2+1].w=(a[k*2+1].w*a[k].flag2+(a[k*2+1].r-a[k*2+1].l+1)*a[k]