进阶线段树之乘法操做

毒瘤梅开二度html

写在前面

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

下面让咱们步入正题

咱们在前面已经介绍过线段树基本操做(单点修改 单点查询 区间修改 区间求值)
可是都是简单的加减运算 若是咱们须要乘法运算呢?htm

  • 若是只是简单的乘法运算 那依然很简单 直接让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;
}
相关文章
相关标签/搜索