線段樹理解

2022-05-25 22:33:11 字數 1747 閱讀 2789

當我覺得我學習演算法剛剛從萌新到入門的時候,一類給定乙個區間然後給定一系列操作的題徹底的打擊了我,那時我才醒悟,程式設計路上,我一直是萌新。

線段樹是乙個具有樹特性的資料結構,它是一顆二叉搜尋樹。如下圖為區間[1,10]所建立的線段樹

將每乙個區間序列二分成小區間,線段樹就儲存小區間的資訊,也就是每個小區間對應線段樹中的乙個結點。比如上圖根節點對應[1,10]

由於線段樹的二分性質,對每乙個子節點來說,左兒子的區間小於右兒子的區間,所以線段樹也是平衡樹。

將需要處理的資訊看成乙個個點,也就是葉子節點,然後通過父親節點來將資訊整合,做到通過樹結構來進行操作對節點資訊進行增刪查改,大大降低複雜度。

最簡單的應用就是記錄區間是否被覆蓋,隨時查詢當前被覆蓋區間的總長度。

既然線段樹利用區間二分建樹,那麼對子區間進行操作,只需要從根節點通過遞迴找到此區間即可,

一次操作時間肯定與樹的高度有關,由於二叉樹搜尋樹的關係,它的高度為log2(n),

所以完成一次操作的時間為o(log(n))。

那麼回想前言中的題目:

給定區間n個數,n<=1000000,給定m個操作,m<=10000,對於每個操作,有兩種情況

用列舉法肯定超時,然而有了線段樹,就可以用log2(n)的時間完成每次操作,資料量很大時,不怕超時。

更多操作,接下來會更細緻的講解。

建一顆樹,當然可以用遞迴和結構體陣列。(還有非遞迴版本,暫時不給出)

int n;

struct

nodenode[

4*n];//注意要開四倍空間

線段樹是完全二叉樹,乙個序號為k的節點,它的左兒子序號為2*k,右兒子序號為2*k+1。、

即  k   --->  k << 1 

--->  k << 1 | 1

對於乙個[ l,r ]區間,結構體中的left,表示此節點代表此區間的左端點l,right表示此區間的右端點r,sum表示此區間的總資訊(這裡是元素之和)

於是可以用遞迴來實現。

**:

void pushup(int n)

void build(int l,int r,int

k)

int m=(l+r)/2

; build(l,m,

2*k);

build(m+1,r,2*k+1

);pushup(k);  //這裡表示回溯函式

}

具體實現看下圖:

圖中紅色箭頭表示build遞迴創造節點,紫色箭頭表示pushup回溯整合資訊,

節點上面表示創造的序號,

節點下面的數字表示節點代表的區間的總和。

這個問題很重要,不然隨意開空間可能會導致溢位。

假設一顆線段樹最下面一層最多有n個節點,是乙個滿二叉樹,那麼此線段樹則有log2(n)+1層。

但如果像[1,10]這樣,不是滿二叉樹,那麼(取整) log2(n) < log2(n)+1 ,所以這樣的線段樹最多有log2(n)+2層。

而二叉樹節點的個數為2log2(n)+2=4*n,所以要開4倍空間。

根據上面所述:當某個節點的left==right時,它是乙個葉子節點,也就是我們需要查詢和修改的物件,於是可以通過遞迴線段樹來找到需要的節點資訊。

理解線段樹

線段樹 二叉搜尋樹 與區間樹 相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。使用線段樹可以快速的查詢某乙個節點在若干條線段中出現的次數,時間複雜度為o logn 對於線段樹中的每乙個非 葉子節點 a,b 它的左兒子表示的區間為 a,a b 2 右兒子表示的區間為 a b...

線段樹初步理解

原本這兩天在搞網路流的.但最近幾次網賽多次遇到了線段樹的題目.意識到線段樹還是重要的.所以今天就初步的了解了線段樹最簡單的應用.單點更新.今天學習線段樹主要是看notonlysuccess大牛的模板 風格非常好.很適合初學線段樹的來參考.網上的一些ppt也不錯.一步一步動態描述線段樹的演算法過程.線...

理解 線段樹 掃瞄線

題目大意 給你n個矩形,求他們的總面積之和。解題思路 哈哈,不過大家別急,為了方便描述,自己動手畫了幾個。四條紅線為矩形的上下底邊,這裡我們稱之為掃瞄線 實際程式設計中不存在,只是乙個概念 如圖所示,要求兩個矩形的面積並,可以把矩形分成幾個小矩形,最後的面積總和為它們的和。對於每個小矩形其 面積s ...