P3373 【模板】线段树 2

更好的题目阅读效果


题目描述

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

将某区间每一个数乘上 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]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值