進階線段樹之乘法操做

毒瘤梅開二度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;
}
相關文章
相關標籤/搜索