进阶线段树之乘法操作

毒瘤梅开二度

写在前面

如果你还不了解什么是线段树 或者你只是简单了解但是并不知道工作原理以及基本操作 请你不要观看这篇博客(如果执意观看可能会引起您的部分不适
在看这篇博客之前可以先看一下 线段树(毒瘤)总结

下面让我们步入正题

我们在前面已经介绍过线段树基本操作(单点修改 单点查询 区间修改 区间求值)
但是都是简单的加减运算 如果我们需要乘法运算呢?

  • 如果只是简单的乘法运算 那依然很简单 直接让lazy标记乘几就好了 后面pushdown的时候将乘法标记下放 然后t[root].sum *= lazy就好了
  • 但是如果既有乘又有加呢? 我们需要考虑是先乘还是先加 因为存在优先级这个东西(乘法比加法高 括号比乘法高)
  • 所以我们将lazy标记改进一下 改进为记录乘法的laz 和 记录加法的add 两个懒惰标记
  • 在想要进行乘法运算的时候很简单 直接pushdown的时候t[root].sum *= laz就好了 但是在进行加法运算的时候 我们需要将原来的add * lazy 再加上add
  • 解释一下原因:
    原来的add 是在当前操作之前进行的 所以优先级应该高于当前add 就像是(a[i]+5)4+6 加5的操作是之前进行的 进行之后再乘4 会将之前的+5一起乘 而后面的+6是当前操作 因此不需要lazy 其他操作大体和加减一样

代码实现

//在做乘法线段树的时候一定要注意取模  一般情况下都会炸int
(如果感觉时间会被卡可以将*2的操作改为<<1 , +1改为|1)
void pushdown(ll p){
	t[p*2].sum = (ll)(t[p].laz * t[p*2].sum + ((t[p*2].r - t[p*2].l + 1)*t[p].add)%mod)%mod;
	t[p*2+1].sum = (ll)(t[p].laz * t[p*2+1].sum + (t[p].add * (t[p*2+1].r - t[p*2 + 1].l + 1))%mod)%mod;
	
	t[p*2].laz = (ll)(t[p*2].laz * t[p].laz)%mod;
	t[p*2+1].laz = (ll)(t[p*2+1].laz * t[p].laz)%mod;
	
	t[p*2].add = (ll)(t[p*2].add*t[p].laz + t[p].add)%mod;
	t[p*2+1].add = (ll)(t[p*2+1].add * t[p].laz + t[p].add) % mod;
	
	t[p].laz = 1,t[p].add = 0;
}
posted @ 2020-07-03 10:04  HISKrrr  阅读(778)  评论(0编辑  收藏  举报