数据结构之线段树入门(单点更新区间查询)
線段樹是學習數據結構必須學習的一種數據結構,在ACM,藍橋等比賽中是經常出現的。利用線段樹解題,會使得題目簡單易理解。而且線段樹是數據結構中比較基礎而且用的很多的一種。
線段樹定義
線段樹是一種二叉搜索樹,與區間樹相似,它將一個區間劃分成一些單元區間,每個單元區間對應線段樹中的一個葉結點。
對于線段樹中的每一個非葉子節點[a,b],它的左兒子表示的區間為[a,(a+b)/2],右兒子表示的區間為[(a+b)/2+1,b]。因此線段樹是平衡二叉樹,最后的子節點數目為N,即整個線段區間的長度。
使用線段樹可以快速的查找某一個節點在若干條線段中出現的次數,時間復雜度為O(logN)。而未優化的空間復雜度為2N,因此有時需要離散化讓空間壓縮。
線段樹圖示
線段樹解決什么問題
線段樹解決的是區間的問題,顧名思義,線段,就代表著一段區間上的問題。而線段樹則是通過樹這種數據結構來解決區間的問題。但是區間問題除了用線段樹,也可以用別的方式來解決。那么線段樹有什么特別之處呢?線段樹可以解決帶有更改的區間問題。最基礎的是兩種,區間求最值以及區間求和。
線段樹的基本內容
線段樹絕對不只是為了解決區間問題的數據結構,事實上,是線段樹多用于解決區間問題,并不是線段樹只能解決區間問題,首先,我們得先明白幾件事情。
每個結點存什么,結點下標是什么,如何建樹。
我們以區間求最值來闡述這個問題。
A數組為[1,8,6,4,3,5].在求最大值的線段樹上建樹后的分布如上圖所示。
可以發現,每個葉子結點的值就是數組的值,每個非葉子結點的度都為二,且左右兩個孩子分別存儲父親一半的區間。每個父親的存儲的值也就是兩個孩子存儲的值的最大值。
我們現在想的是每個節點如何存儲數據以及我們怎么能夠快速的找到某個節點的孩子節點以及父親節點呢?這也就是線段樹的重點和難以理解的地方了。
對于一個區間[l,r]來說,最重要的數據當然就是區間的左右端點l和r,但是大部分的情況我們并不會去存儲這兩個數值,而是通過遞歸的傳參方式進行傳遞。這種方式用指針好實現,定義兩個左右子樹遞歸即可,但是指針表示過于繁瑣,而且不方便各種操作,大部分的線段樹都是使用數組進行表示,那這里怎么快速使用下標找到左右子樹呢。我們對上圖每一個存儲結構編號。如下圖所示:
值得一問的是,為什么最下一排的下標直接從9跳到了12,道理也很簡單,中間其實是有兩個空間的呀!!雖然沒有使用,但是他已經開了兩個空間,這也是為什么無優化的線段樹建樹需要4倍的存儲空間,一般會開到4 * n的空間防止RE。
從上圖我們可以看到,假設節點為cur,那么它的左孩子節點為(2 * cur),右孩子節點為(2 * cur+1)。因為左子樹都是偶數,所以我們常用位運算來尋找左右子樹。
k<<1(結點k的左子樹下標)
k<<1|1(結點k的右子樹下標)
明白了一些基本的常識,那就要學著建樹了。
線段樹的基本操作
這種在線的樹結構,一般就是兩種操作,更新和查詢。
①點更新
如何實現點更新,我們先不急看代碼,還是對于上面那個線段樹,假使我把a[3]+7,則更新后的線段樹應該變成
更新了a[3]后,則每個包含此值的結點都需要更新,那么有多少個結點需要更新呢?根據二叉樹的性質,不難發現是log(k)個結點,這也正是為什么每次更新的時間復雜度為O(logN),那應該如何實現呢,我們發現,無論你更新哪個葉子節點,最終都是會到根結點的,而把這個往上推的過程逆過來就是從根結點開始,找到左子樹還是右子樹包含需要更新的葉子節點,往下更新即可,所以我們還是可以使用遞歸的方法實現線段樹的點更新。
update代碼如下:
②區間查詢
說完了單點更新肯定就要來說區間查詢了,我們知道線段樹的每個結點存儲的都是一段區間的信息 ,如果我們剛好要查詢這個區間,那么則直接返回這個結點的信息即可,比如對于上面線段樹,如果我直接查詢[1,6]這個區間的最值,那么直接返回根節點信息返回13即可,但是一般我們不會湊巧剛好查詢那些區間,比如現在我要查詢[2,5]區間的最值,這時候該怎么辦呢,我們來看看哪些區間是[2,5]的真子集。如下圖所示
畫黃顏色的就是[2,5]的真子集,但是我們可以看到[4,4]和[5,5]是被[4,5]包括的,而且[4,5]的最值我們也是知道的,這樣我們就只查尋三個區間就可以了。我們還是從根節點開始往下遞歸,如果當前結點是要查詢的區間的真子集,則返回這個結點的信息且不需要再往下遞歸了,這樣從根節點往下遞歸,時間復雜度也是O(logN)。
代碼如下:
線段樹的基本操作就是這些了。自己動手模擬一下然后多做題就能掌握了。
參考博客:https://www.cnblogs.com/xenny/p/9801703.html
努力加油a啊,(o)/~
總結
以上是生活随笔為你收集整理的数据结构之线段树入门(单点更新区间查询)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二分搜索(折半搜索),lower_bou
- 下一篇: Non-zero CodeForces