1 引入
傳統線段樹能夠透過打標記實現區間修改的條件有兩個:
- 能夠快速處理標記對區間詢問結果的影響;
- 能夠快速實現標記的合併。
有的區間修改不滿足上面兩個條件。
但存在一些奇妙的性質,使得序列每個元素被修改的次數有一個上限。
如果我們保證每暴力 \(O(\log n)\) 修改一次的時候都能修改到一個值(也就是在一個數的修改次數達到上界的時候不再修改她),那麼就可以均攤 \(O(n\log\times \text{修改上限})\) 解決。
具體到實現,可以考慮線上段樹每個節點上記錄一個東西(需要依題而定),用來表達對應區間內是否每個元素都達到修改次數上限。區間修改時暴力遞迴到葉子節點,如果途中遇到一個節點,這個節點的對應區間內每個元素都達到修改次數上限則在這個節點直接 return 掉。
2 關於勢能在時間複雜度計算上的應用
首先定義一個勢能函式初始值就是每個元素至多被修改的次數之和。
每次操作如果勢能都是不增的,那麼整體的複雜度就不會超過初始勢能函式的值。
3 應用
p.s. 下面都是修改操作,查詢操作應該是傳統線段樹能做的她都能做(?
3.1 區間取模
顯然每次取模每次都讓原數至少減少一半,修改上限就是 \(\log V\)。
具體到實現,我們維護每個區間的最大值,如果區間最大小於模數,那麼就可以不用遞迴下去了。
3.2 區間開方
3.2.1 Solution1 維護是不是全 \(0/1\)
首先,對於任意數開方,可以在至多 \(\log\log n\) 次內變為 \(0/1\)。
why? 其實也很好理解,因為開方一次相當於 \(\frac 12\) 方。所以就是問 $\log n $ 的最多能除 \(\frac 12\) 幾次,所以就是 \(\log\log n\)。
與 3.1 類似,還是維護區間最大值就行了。
3.2.2 Solution2 維護是不是全相等
其實這道題還有一種維護方式。
直接維護區間最大值、最小值,以此來看區間是不是全部相同,如果是就直接打區間覆蓋的標記。
3.2.3 區間開方,區間加法
現在我們先用勢能去理解一下上面兩種維護方式。
對於第一個,對於每個節點其勢能函式應該是該區間還不是 \(0/1\) 的個數。
對於第二個,對於每個節點其勢能函式應該是該區間不同的元素個數。
現在加上區間加之後,我們發現第一個勢能函式會增加了,時間複雜度假了,但是第二個並不會!所以說,如果有區間加就只能用第二種維護方式。
但是還沒完,對於這樣的資料:3434,開方為 1212,再加 2 為 3434,這樣就會迴圈。
解決辦法是直接特判一下這種情況。
對於 \(\sqrt{max}=\sqrt{min}\) 的情況,打區間覆蓋標記。
對於 \(\sqrt{max}=\sqrt{min}+1\) 的情況,相當於區間減 \(max-\sqrt{max}\),打區間減標記。
3.3 區間除法
與取模類似每次都讓原數至少減少一半,修改上限同樣也是 \(\log V\)。
注意,這裡除法的結果是要數學上的向下取整的話,如果是正數最後會停在 \(0\),反之會停在 \(-1\)。
如果是用 3.2.1 的維護方式,需要分別維護區間是不是全 \(0/-1\),有點麻煩。
下面還是考慮 3.2.2。
還是特判 \(max-min=1\) 的區間.
對於 \(max/d=min/d\) 的情況,打區間覆蓋標記。
對於 \(max/d=min/d+1\) 的情況,相當於區間減 \(max-max/d\),打區間減標記。
4 總結
對於常見的數學運算(比如取模就不算),一般都可以考慮 3.2.2 維護方式,即:
考慮維護 \(min,max,max-min\),然後邊界情況就可以打標記,非邊界遞迴兩邊。