專欄 | 九章演算法
網址 | www.jiuzhang.com
線段樹專題
線段樹入門問題
給出數列[1 4 2 3],求給定區間的最大值
例:query(0,1) = 4 query(2,3) = 3 query(0,3) = 4
解題思路分析
一道題可不可以用線段樹來做,基本是看這道題的操作有沒有區間的性質。也就是在一個區間上的操作是否可以轉化為兩個子區間上的操作。
從這題可以看出
區間(a,b)的最大值和區間(b,c)的最大值中
取較大的就是區間(a,c)的最大值
很明顯可以看出這個操作是具有區間的性質。
套路:幾種常見的線段樹的套路
- 求區間的和,積,最大值,最match小值,gcd等
- 以當前結點的值作為結點處理,比如給出N個數,再給一個數,問比這個數大的有多少個(當然,用樹狀陣列可以很好的處理,但有修改時,線段樹就會方便很多)
- 區間加減同一個值,或者區間同時賦一個值(在面試中,通常不會問到,演算法競賽中會經常用到)
構造:一顆線段樹的構造就是根據區間的性質的來構造的
區間劃分大概就是上述的區間劃分。可以看出每次都將區間的長度一分為二,數列長度為n,所以線段樹的高度是log(n),這是很多高效操作的基礎。
上述的區間儲存的只是區間的左右邊界。我們可以將區間的最大值加入進來。
區間的第三維就是區間的最大值
加這一維的時候只需要在建完了左右區間之後,根據左右區間的最大值來更新當前區間的最大值即可。
因為每次將區間的長度一分為二,所有創造的節點個數為
n + 1/2 n + 1/4 n + 1/8 n + ...
= (1 + 1/2 + 1/4 + 1/8 + ...) n
= 2n
所以構造線段樹的時間複雜度和空間複雜度都為O(n)
程式碼1:線段樹構造程式碼模板
區間查詢:構造線段樹的目的就是為了更快的查詢。
給定一個區間,要求區間中最大的值。
線段樹的區間查詢操作就是將當前區間分解為較小的子區間,然後由子區間的最大值就可以快速得到需要查詢區間的最大值。
query(1,3) = max(query(1,1),query(2,3)) = max(4,3) = 4
上述例子將(1,3)區間分為了(1,1)和(2,3)兩個區間,因為(1,1)和(2,3)區間的最大值事先已經記錄好了,所以直接拿來用就可以了。
層數:每一層最多查詢4個區間
考慮長度為16的序列構造成的線段樹,區間(0,15)。查詢區間(1,14)。
第一層會查詢 (1,7) (8,15)
第二層會查詢 (1,3) (4,7) (8,11) (12,14)
第三層會查詢 (1,1) (2,3) (12,13) (14,14)
第四層會查詢 (1,1) (14,14)
因為是連續的,中間那部分會直接算出來,然後兩邊的兩端繼續往下,還是4個區間。
因為線段樹的高度為log(n),所以查詢的時間複雜度為O(log(n))
程式碼2:線段樹區間查詢模板
單點更新:更新序列中的一個節點
如何把這種變化體現到線段樹中去?
例如,將序列中的第4個點更新為5,要變動3個區間中的值,分別為[3,3],[2,3],[0,3]
可以這樣想,改動一個節點,與這個節點對應的葉子節點需要變動。因為葉子節點的值的改變可能影響到父親節點,然後葉子節點的父親節點也可能需要變動。
所以需要從葉子節點一路走到根節點,去更新線段樹上的值。因為線段樹的高度為log(n),所以更新序列中一個節點的複雜度為log(n)。
程式碼3:線段樹單點更新模板
如果需要區間的最小值或者區間的和。和構造的時候同理。
相關Lintcode面試題
線段樹構造
www.lintcode.com/zh-cn/probl…
www.lintcode.com/zh-cn/probl…
線段樹單點更新
線段樹區間查詢
www.lintcode.com/zh-cn/probl…
www.lintcode.com/zh-cn/probl…
線段樹綜合
www.lintcode.com/zh-cn/probl…
www.lintcode.com/zh-cn/probl…
www.lintcode.com/zh-cn/probl…
www.lintcode.com/zh-cn/probl…
www.lintcode.com/zh-cn/probl…
歡迎關注我的微信公眾號:九章演算法(ninechapter)。
精英程式設計師交流社群,定期釋出面試題、面試技巧、求職資訊等