上一節介紹了點修改與區間查詢的線段樹,事實上,線段樹還可以做得更多。本節討論區間修改問題。
給出乙個$n$個元素的陣列$a_1,a_2,...,a_n$,你的任務是設計乙個資料結構,支援以下兩種操作:
點修改只會影響到$logn$個結點,但區間修改在最壞情況下會影響到樹中的所有結點,比如,如果對整個區間執行$add$操作,所有結點的$sum$都會發生改變。怎麼辦呢?
維護的資訊也需要發生改變,如果仍然用$sum[o]$表示「結點$o$對應區間中所有數的和」,則$add$操作在最壞情況下會修改所有的$sum$(不管$add$有沒有分解)。解決方法是把$sum[o]$的定義改成「如果只執行結點$o$及其子孫結點的$add$操作,結點$o$對應區間中所有數之和」。這樣的附加資訊仍可以方便地維護,而且每個原始$add$所影響到的結點數目變成了$o(h)$。
維護的**如下:
1void maintain(int o, int l, intr)2
78int cl, cr, v; //
區間修改,[cl,cr] += v;
9void update(int o, int l, int r) //
1018
maintain(o, l, r);
19 }
注意,此時add操作的遞迴邊界結點的minv是對的,其子節點(即子區間)的minv是不準確的,因為沒有考慮add操作的影響。
查詢操作總體上跟之前相同,但是還得考慮祖先結點對其的影響。因此,我們在遞迴查詢中新增乙個引數$add$,表示當前區間的所欲祖先結點$add$值之和(不包括本身,因為本身的add標記在maintain已考慮),方法如下:
1int ql, qr; //
區間查詢,min
2int query(int o, int l,int r, int
add)
314 }
建樹的操作與點修改一模一樣,不再贅述。
線段樹二(區間修改)
概述 區間修改即將乙個區間內所有值改為乙個值 或加上乙個值 為了執行快速,我們通常用 懶 標記維護整個區間值的情況,在需要是再將這個 懶 標記傳到該節點的兩個子節點上。模版 此為在整個區間上加上乙個值 洛谷p3372 include include include include include i...
線段樹 二 區間乘 區間加
放 注意點 注意運算子優先順序 比如 a b p 是b先mod p再與a相乘 a 1 1是1 1再a位移 a 1 a 2 a 1 1 a 2 1 參見 線段樹v2.0 支援區間加 區間乘 區間和查詢 include include include define n 1000010 using nam...
線段樹(2)區間修改
快速序列操作i,給出乙個n個元素的陣列a1,a2,an,你的任務是設計乙個資料結構支援一下兩種操作 set l,r,v 把al,al 1,ar的值全部修改為v v 0 query l,r 計算子串行al,al 1,ar的元素和 最小值和最大值。include include using namesp...