線段樹入門

2021-09-26 11:00:46 字數 1537 閱讀 1192

有一類區間問題可以抽象成如下模型。 給定包含 n個數的陣列 a1,a2,⋯an​。有兩種操作

查詢區間 [l,r] 最小的數。

修改第 ai為 x。

這裡,為了解決這個問題,我們介紹一種靈活的資料結構——線段樹。

我們用一棵二叉樹來表示線段樹,線段樹中的每個結點都表示乙個區間。每個非葉子結點都有左右兩棵子樹,分別對應區間的 「左半」 和 「右半」。為了方便起見,我們給根結點編號為 1。對於每個結點,其左結點的編號為 2i,其右結點的編號為 2i+1。

對於乙個結點,如果其表示的區間為 [l,r]。分情況如果 l=r,那麼這個是乙個葉子結點。否則令 mid=⌊,左兒子對應的區間為 [l,mid],右兒子對應的區間為 [mid+1,r],這一思想有點類似二分。下面就是 n=10 的時候的線段樹。

假定根結點表示長度為 2h 的區間,不難發現,樹的第 i 層有 2i 個結點,每個結點對應乙個長度為 2h-i 的區間。最大層的編號為 h,結點總數為 1+2+4+8+⋯+2h = 2h+1 - 1,略小於區間長度的兩倍。而當整個區間長度不是 2 的整數冪時,雖然葉子結點不在同一層,但樹的最大層編號和結點總數仍滿足上述結論。

前面構建的線段樹,只是展示了線段樹中各結點所對應的區間,但是對於用到線段樹的大部分題目來說,這些線段所擁有的附加資訊才是重頭戲。比如要維護區間最小值問題,我們用乙個額外的陣列minv記錄每個結點對應的區間的最小值。 對於葉子結點,最小值就是乙個數。而對於非葉子結點,區間的最小值就是左兒子的最小值和右兒子最小值中的最小值。

可以發現這個構建過程是乙個遞迴的過程,父節點的資訊需要用子節點去更新,所以我們需要先遞迴的構建好左右子樹。見下面**。

const

int maxn =

10010

;int minv[

4* maxn]

, a[maxn]

;// id 表示結點編號,l, r 表示左右區間

void

build

(int id,

int l,

int r)

int mid =

(l + r)

>>1;

build

(id <<

1, l, mid)

;build

(id <<1|

1, mid +

1, r)

; minv[id]

=min

(minv[id <<1]

, minv[id <<1|

1]);

}

有乙個需要特別注意的地方地方,雖然線段樹中總的結點數是區間長度的兩倍,但是實際上,我們結點的編號不一定是連續的,所以需要開更多的記憶體。而 4 倍這個數字可以通過比較複雜的數學推導得出來。這裡不做過多的推導了。 所以,整個建樹的過程,時間複雜度是 o(n)。

線段樹入門

線段樹 interval tree 是把區間逐次二分得到的一樹狀結構,它反映了包括歸併排序在內的很多分治演算法的問題求解方式。上圖是一棵典型的線段樹,它對區間 1,10 進行分割,直到單個點。這棵樹的特點 是 1.每一層都是區間 a,b 的乙個劃分,記 l b a 2.一共有log2l層 3.給定乙...

線段樹入門

學習下 線段樹的入門級 總結 線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。對於線段樹中的每乙個非葉子節點 a,b 它的左兒子表示的區間為 a,a b 2 右兒子表示的區間為 a b 2 1,b 因此線段樹是平衡二叉樹,最後的子節點數目為...

線段樹 入門

首先線段樹形象來說就是將陣列看成乙個線段,然後不斷的進行分割,儲存在樹中的不同節點上,有點類似於b 樹的定義吧 觀察上圖,首先將整個陣列的某種資訊 最大值或者最小值等 儲存在根節點,對應 1,8 然後對 1,8 線段進行平分,得到 1,4 和 5,8 兩個線段,掛在樹的第二層。這樣節點2儲存了陣列中...