週中訓練筆記11 線段樹總結

2021-08-09 09:03:46 字數 2210 閱讀 5953

線段樹專題接近尾聲了,是時候總結一波了,說來慚愧,線段樹專題差不多都是參照題解才做出來的,雖然知道是套模板但是具體細節真的很拿人啊。。。

主要總結一下線段樹的模板吧,題目的**實現都要以模板為框架構造:

首先提出乙個問題: 

給你n個數,有兩種操作:

1:給第i個數的值增加x

2:詢問區間[a,b]的總和是什麼?

輸入描述

輸入檔案第一行為乙個整數n,接下來是n行n個整數,表示格仔中原來的整數。接下乙個正整數q,再接

下來有q行,表示q個詢問,第乙個整數表示詢問代號,詢問代號1表示增加,後面的兩個數x和a表示給

位置x上的數值增加a,詢問代號2表示區間求和,後面兩個整數表示a和b,表示要求[a,b]之間的區間和。

樣例輸入

47 6 3 5

21 1 4

2 1 2

樣例輸出

17資料範圍

1 <= n,q <= 100000

看到這個問題,最樸素的想法是用乙個陣列模擬,求和時 [ a , b ]中逐個累加 , 最後輸出 。

但是,由於資料量比較大,時間複雜度太高,時間上無法承受。

這時我們可以用線段樹( segment tree ),這種特殊的資料結構解決這個問題。

那麼什麼是線段樹呢?

這就是一棵典型的線段樹

一 般的線段樹上的每乙個節點t[a , b],代表該節點維護了原數列[ a , b ]區間的資訊。對於每乙個節點他至少有

三個資訊:左端點,右端點,我們需要維護的資訊(在本題中我們維護區間和)。由於線段樹是乙個二叉樹,而且是乙個平衡二叉樹,如果當前結點的編號是i,左端點為l ,右端點為 r , 那麼左兒子的 編號為 i*2 ,左端點為 l ,右端點為 (l + r)/2 ; 同理右兒子的 編號為 i*2+1,左端點為(l+r)/2 ,右端點為 r

。如果當前結點的左端點等於右端點,那麼該節點就是葉子節點,直接在該節點賦值即可。顯然線段樹是遞迴定義的。

線段樹就是這樣一種資料結構,講乙個大區間分為若干個不相交的區間,每次維護都在小區間上處理,並且查

詢也在這些被分解的區間中資訊合併出我們需要的結果,這就是線段樹高效的原因。

線段樹的儲存:

線段樹的儲存可用鍊錶和陣列模擬。(採用陣列寫法,便於理解)

1.鍊錶儲存:

struct node

;2.陣列模擬

struct tree

tr[maxn << 2];

注意:陣列的空間要開四倍大小,防止訪問越界,(理論上大於maxn的最小2x的兩倍)

建樹:線段樹的構建是自頂點而下,即從根節點開始遞迴構建,根據線段樹定義,當左端點等於右端點時(達到遞迴邊界),直接賦值即可,回溯時也要維護區間,**如下:

void build_tree ( int x , int y , int i )

}維護樹:

維護樹的方法也很好理解,如果目標更新節點在左兒子裡,去左兒子中查詢;反之,在右兒子中。不斷遞迴,知道找到需要維護的節點,更新它,回溯是一路更新回來。這就是維護的過程,**如下:

void update_tree ( int q , int val , int i )

else //當前結點是非葉子結點

else if( q > mid ) //目標節點在右兒子中

tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum; //回溯}}

查詢樹:

題目中讓我們查詢區間求和,不難想到如果當前結點的區間完全被目標區間包含,直接返回當前結點的sum值,

否則分類討論。具體過程通過以下**理解:

long long query_tree ( int q , int w , int i )

else if (w <= mid ) //完全在右兒子

else //目標區間在左右都有分布}}

主程式:

int main ( )

else

}return 0 ;

}線段樹的性質:

假設線段樹處理的數列長度為n,那麼總結點數不超過2*n(滿二叉樹是最大情況);

線段分解數量級:線段樹能把任意一條長度為m的線段分為不超過2log2(m)條線段(我們知道乙個很大的數,log一下就變小了),這條性質使線段樹的查詢與修改複雜度都在o(log2(n))的範圍內解決。

由於線段樹是一顆二叉樹,深度約為log2(n)左右。

綜上,線段樹空間消耗o(n),由於它深度性質,使它在解決問題上有較高的效率。

週中訓練筆記

rand 函式 rand n 範圍 0 n 1 n rand m n 1 範圍n m 線段樹的概括 1.是乙個完全二叉樹 2.主要用於解決解決連續區間的動態查詢問題 現在對於線段樹的認識還很侷限,所以概括的也非常籠統,接下來的幾天會繼續研究線段樹的。然後就是今天的廣西邀請賽重現賽的題 今天因為下午有...

週中訓練筆記(四)

線段樹總結 線段樹儲存的是區間的資訊然後在可以進行區間的各種操作。對於節點a n 它的左兒子為a 2 n 右兒子為a 2 n 1 假如這個節點所表示的區間為 1,5 那麼它左兒子表示的區間為 1,3 右兒子表示的區間為 4,5 公式為mid l r 2,左兒子表示的區間為 l,mid 右兒子表示的區...

週中訓練筆記19 樹形DP總結

樹形dp暫時告一段落,今天總結了一下 首先,樹形dp 樹 dp,是一種二維的dp題目,也可以結合揹包問題,因為子樹的數量不確定,所以一般用vector來儲存子節點或子樹個數。平時作的動態規劃都是線性的或者是建立在圖上的,線性的動態規劃有二種方向既向前和向後,相應的線性的動態 規劃有二種方法既順推與逆...