線段樹專題接近尾聲了,是時候總結一波了,說來慚愧,線段樹專題差不多都是參照題解才做出來的,雖然知道是套模板但是具體細節真的很拿人啊。。。
主要總結一下線段樹的模板吧,題目的**實現都要以模板為框架構造:
首先提出乙個問題:
給你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來儲存子節點或子樹個數。平時作的動態規劃都是線性的或者是建立在圖上的,線性的動態規劃有二種方向既向前和向後,相應的線性的動態 規劃有二種方法既順推與逆...