線段樹:
線段樹其實是乙個二叉搜尋樹,它儲存的是乙個區間的資訊
每個節點以結構體的方式儲存
結構體包括區間的左右端點外加區間和
其它看情況加區間要維護的資訊
線段樹的基本思想是二分
特殊性質有:
每個節點的左孩子的區間範圍確定
對於節點k,左孩子節點為2k,右孩子為2k+1,這符合完全二叉樹的性質
線段樹的基本操作:建樹,單點查詢,單點修改,區間查詢,區間修改
1.建樹
struct node
tree[
4*n+1]
;
樹應該開4倍空間
主體思路
對於二分到的結點,給他左右端點確定範圍
如果是葉子結點,儲存要維護的資訊
狀態合併
void
creat_tree
(int l,
int r,
int k)
int m=
(l+r)/2
;creat_tree
(l,m,k*2)
;creat_tree
(m+1
,r,k*2+
1); tree[k]
.sum=tree[
2*k]
.sum+tree[k*2+
1].sum;
}
2.單點查詢
如果左端點等於右端點則是葉節點,是我們要查詢的值,直接返回該值即可
如果不相等則求出其左右端點的中間值,如果比mid小遞迴左孩子,否則遞迴右孩子
int
find_tree
(int k)
int mid=
(tree[k]
.l+tree[k]
.r)/2;
if(k<=mid)
else
return
find_tree
(k*2+1
);//否則找右孩子
}
3、單點修改
原理=單點查詢+建樹的結合
void
changdata
(int k,
int y)
//k要查詢的位置,y是要增加的值
int m=
(tree[k]
.l+tree[k]
.r)/2;
if(x<=m)
changdata(2
*k,y)
;else
changdata(2
*k+1
,y);
tree[k]
.sum=tree[k*2]
.sum+tree[k*2+
1].sum
}
4.區間查詢
int ans=0;
void
sum(
int k,
int x,
int y)
int m=
(tree[k]
.l+tree[k]
.r)/2;
if(x<=m)
sum(
2*k,x,y);if
(y>m)
sum(
2*k+
1,x,y)
;}
5、區間修改
引入懶惰標記
void
down
(int k)
void
add(
int k)
if(tree[k]
.f)down
(k);
//懶標記下傳。只有不滿足上面的if條件才執行,所以一定會用到當前節點的子節點
int m=
(tree[k]
.l+tree[k]
.r)/2;
if(a<=m)
add(k*2)
;if(b>m)
add(k*2+
1); tree[k]
.w=tree[k*2]
.w+tree[k*2+
1].w;//更改區間狀態
}
線段樹學習筆記
線段樹是一種 二叉搜尋樹 與區間樹 相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。使用線段樹可以快速的查詢某乙個節點在若干條線段中出現的次數,時間複雜度為o logn 而未優化的 空間複雜度 為2n,因此有時需要離散化讓空間壓縮。以下筆記摘自lcomyn神犇部落格 1....
線段樹學習筆記
本文筆記在參考一步一步理解線段樹 tenos的基礎上形成 線段樹,也是二叉搜尋樹的一種,是基於陣列,但是優於陣列的一種資料結構。同時結合預處理 時間複雜度一般在o n 使得從原來陣列的o n 的查詢和更新複雜度降到了o logn 在處理很大資料量的資料更新和查詢最值方面變得簡單,值得一提的是,它的構...
線段樹學習筆記
線段樹是一種維護區間的資料結構,且滿足二叉樹的全部性質 下圖是一棵維護區間 1 6 1,6 的線段樹 格式 idl ri dl r我們可以發現,對於每個節點 k k 來說,其左節點編號為2k role presentation style position relative 2k2 k,右節點編號為...