宣告 :
線段樹作為一種十分常用的資料結構,在noip、noi中廣泛的出現,所以在這裡對線段樹進行簡單的講解。
線段樹支援對乙個數列的求和、單點修改、求最值(最大、最小)、區間修改(需要lazy標記,暫不講解)。這幾種操作,時間複雜度是(logn)級別的,是一種十分優秀的資料結構。因此其獲得了廣泛的應用。
定義:顧名思義,它是一種樹形結構,但每段不是平常所學的乙個點乙個點的樹,而是一條一條的線段,每條線段包含著一些值,其中最主要的是起始和結束點記作 l,r 即左端點和右端點。
那麼該如何劃分線段樹呢?我們採用二分的思想,即每次將一段取半,再進行接下來的操作,這樣綜合了操作的方便程度和時間複雜度。因為線段樹通過二分得來,所以線段樹是一顆二叉樹。這也方便了對兒子查詢。下面是線段樹的圖,有利於理解:
建樹:僅僅知道模型還是不夠的,建樹的過程是線段樹的關鍵(build(1,1,n))從一號開始,左端是1,右端是n
位運算 i<<1 等效於 i/2 (i<<1)|1 等效於 i/2+1 加速。。。
inline void update(int數列求和:這是線段樹的乙個典型演算法,其他的很多應用都是從中轉化的。i)更新i節點維護的值(求和,最大……)
inline
void build(int i,int l,int r)//
inline 還是加速
int mid=(l+r)/2;//
因為是二叉樹所以以中點為分割點
build(i<<1,l,mid);//
根據二叉樹的知識,左兒子是i/2右兒子是i/2+1
build((i<<1)|1,mid+1
,r);
update(i);
}
為了求和我們定義乙個函式sum(inti,intl,intr)i是開始的樹節點,我們預設為1。l是區間的開始點,它的標號是在數列中的標號,r是結束點其餘同l。帖下**:
inline int sum(int i,int l,int r)//區間求最值和區間求和大致相同,自己看一下inline 又是加速
inline int max(int i,int l,int單點更新:和區間不同,但基本思想還是一樣的。r)
inline void add(int i,int k,int v)//最後貼下全部的**基本可以做模板了。。當前計算到的點為i,把數列中的第k個元素加v
int mid=(node[i].l+node[i].r)/2
;
if(k<=mid) add(i<<1,k,v);//
若k小於mid則k在樹節點i的左子樹中
else add((i<<1)|1,k,v);//
反之 update(i);//
更新}
#include#includeusing
namespace
std;
struct
tree;
tree node[
100];
int n,m,a[100
];inline
void update(int
i)inline
void build(int i,int l,intr)
int mid=(l+r)/2
; build(i
<<1
,l,mid);
build((i
<<1)|1,mid+1
,r);
update(i);
}inline
void add(int i,int k,int
v)
int mid=(node[i].l+node[i].r)/2
;
if(k<=mid) add(i<<1
,k,v);
else add((i<<1)|1
,k,v);
update(i);
}inline
int sum(int i,int l,int
r)inline
int max(int i,int l,int
r)int
main()
}
C 線段樹 高階資料結構
線段樹是一種平衡二叉搜尋樹 完全二叉樹 它將乙個線段區間劃分成一些單元區間。對於線段樹中的每乙個非葉子節點 a,b 他的左兒子表示的區間為 a,a b 2 右兒子表示的區間為 a b 2 1,b 最後的葉子節點數目為n,與陣列下標對應。線段樹的一般包括建立 查詢 插入 更新等操作,建立規模為n的時間...
Foreign 資料結構C 線段樹
首先,d操作為刪除操作顯然不可做,又發現這道題可以離線處理,那麼我們考慮倒著來,維護加入操作。那麼這時候,d操作就變為了合併操作,那麼這時候我們只需要維護乙個 可以支援單點修改 查詢第 k 大 資訊可合併的資料結構即可。顯然構建若干棵權值線段樹即可!對於每個聯通塊維護一棵線段樹,用並查集判斷兩點是否...
資料結構 線段樹
啦啦啦啦啦啦線段樹是個好東西 好吧並沒有什麼好的 但貌似還是很好啊 線段樹就是一棵樹!顧名思義 又是這個詞 就是求關於一段的某些什麼什麼東西。比如區間最大值啊什麼的。引用百科知識 線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。對於線段樹中...