線段樹的初學認知及操作步驟

2021-09-25 12:43:05 字數 2318 閱讀 9024

線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。

使用線段樹可以快速的查詢某乙個節點在若干條線段**現的次數,時間複雜度為o(logn)。而未優化的空間複雜度為2n,實際應用時一般還要開4n的陣列以免越界,因此有時需要離散化讓空間壓縮。

線段樹主要作用就是單點,區間查詢和修改值。它的實現複雜度比較低,應用也比較廣泛。

單點修改和查詢基本步驟:1.建樹,將陣列變為樹的形式。當區間為1時即為葉子節點本身

2.更新單點值

3.查詢單點值。

區間修改,多乙個步驟,懶惰標記並且傳遞。

為什麼要用線段樹?

對於乙個資料比較小的,我們可以遍歷陣列區間找到最小值,時間複雜度是o(n),額外的空間複雜度o(1)。當資料量特別大,而查詢操作很頻繁的時候,耗時可能會不滿足需求。

當然我們也可以使用乙個二維陣列來儲存提前計算好的區間[i,j]內的最小值,那麼預處理時間為o(n^2),查詢耗時o(1),但是需要額外的o(n 2)空間,當資料量很大時,這個空間消耗是龐大的,而且當改變了陣列中的某乙個值時,更新二維陣列中的最小值也很麻煩。

我們可以用線段樹來解決這個問題:預處理耗時o(n),查詢、更新操作o(logn),需要額外的空間o(n)

基本操作:

建樹:

void build(int root,int l,int r)

else

單點更新:

void upade(int root,int l,int r,int l,int r,int val)}查詢

int query(int root,int l,int r,int l,int r)

treep[root]=ans1+ans2;

return tree[root];

}

區間更新:

區間更新是指更新某個區間內的葉子節點的值,因為涉及到的葉子節點不止乙個,而葉子節點會影響其相應的非葉父節點,那麼回溯需要更新的非葉子節點也會有很多,如果一次性更新完,操作的時間複雜度肯定不是o(lgn),例如當我們要更新區間[0,3]內的葉子節點時,需要更新出了葉子節點3,9外的所有其他節點。為此引入了線段樹中的懶惰標記概念,這也是線段樹的精華所在。

懶惰標記:每個節點新增加乙個標記,記錄這個節點是否進行了某種修改(這種修改操作會影響其子節點),對於任意區間的修改,我們先按照區間查詢的方式將其劃分成線段樹中的節點,然後修改這些節點的資訊,並給這些節點標記上代表這種修改操作的標記。在修改和查詢的時候,如果我們到了乙個節點p,並且決定考慮其子節點,那麼我們就要看節點p是否被標記,如果有,就要按照標記修改其子節點的資訊,並且給子節點都標上相同的標記,同時消掉節點p的標記。

懶惰標記的意義

代表了這個結點的值已經被更新過了, 但是沒有進行子樹的結點值更改操作, 用lazy陣列標記一下.

所以, 每次進行值的更新和查詢操作, 每到乙個有 lazy 標記的結點, 必須進行向下更新.

如果[3, 9]這個區間被修改的話,那麼下圖中的所有綠色的結點的值都要得到重新計算的:

但是實際上是沒有必要這麼做的——我們可以引進一種叫做lazy tag,即延遲標記的東西——的確對於[3, 9]這樣一次修改操作,我可以只去修改如下圖中橙色的結點,但是在這個基礎上,我要在[3, 9]分解出的4個區間[3, 3], [4, 5], [6, 8], [9, 9]所對應的結點上做乙個延遲標記,表示「之前有一次操作需要將這棵子樹中的所有結點的**都進行修改,但是因為還沒有用到這棵子樹中的值所以我暫時不去修改」,

但是這些懶惰標記(即延遲標記,以下將不在區分二者)又有什麼用呢?

其實就是乙個暫時不處理,等到需要用到的時候再進行處理的思想。比如你之前說道的詢問了[6, 7]這個區間,那麼我再從上往下分解的時候,你會發現[6, 8]這個區間上有乙個懶惰標記,那麼你就應該進行乙個懶惰標記的『下放操作』——也就是說去修改[6, 8]這個結點的左右兒子的值,並且同時給左右兒子新增上新的懶惰標記,然後將[6, 8]的懶惰標記去掉。

也就是說——本來[6, 8]的左右兒子早在之前的修改操作中就需要一同進行修改的,但是因為還沒有用到單獨的[6, 7],[8, 8]之類的區間的原因,所以我可以暫時不處理這些結點的修改,而是用乙個懶惰標記記錄下來這些結點需要進行修改這件事情。然後在之後要用到這些值的時候再進行這些操作。

懶惰標記做法:

void pushdown(int root,int l,int r)
參考部落格:

線段樹的基本操作

點更新 1 include 點更新2 include 3 include 4 5using namespace std 67 const int n 10000 8 intn,m,a n 9struct node 10tree 4 n 1415 void build int id,int l,int...

線段樹的區間操作 板

區間操作 struct node tr maxn 2 節點型別 void pushup int m void build int m,int l,int r 如果只有乙個節點 int mid l r 1 build m 1,l,mid build m 1 1,mid 1,r 建好左右半邊 pushu...

線段樹的建樹 更新 查詢操作

模板題sdut oj 3771 陣列計算機 description blue 有乙個神器的機器,這個機器可以讀入乙個陣列,並按照使用者要求快速地進行陣列的處理和計算,它支援如下兩種操作 操作 1 把陣列中第 p 個元素的值增加 v。操作 2 計算陣列中 l,r 區間內所有數的和。這個機器就是這麼的神...