線段樹基礎(1)

2021-06-19 20:04:29 字數 1566 閱讀 1186

訓練了三周線段樹,對線段樹的點操作、斷更新和常見應用範圍進行總結,並記錄一些技巧。

線段樹是一種二叉搜尋樹,也是一顆平衡樹。樸素的遞迴寫法是對於每乙個非葉子節點[l,r],取m=(l + r)/2,左孩子為[l,m],右孩子為[m+1,r],使用堆式儲存,空間大小為4n。一些define:

#define lc rt<<1

#define rc rt<<1|1

#define lson l,m,rt << 1

#define rson m + 1,r,rt << 1 | 1

出於節省儲存空間考慮,節點的區間左端點值(l)和右端點值(r)可以通過遞迴時計算得出,不需要保留;節點的左兒子(lc)和右兒子(rc)因為堆式儲存,也可以由當前節點(rt)推出。所以線段樹表示為乙個或多個存關鍵字的陣列。

以hdu 1166(敵兵布陣)(點更新,區間和)為例,介紹線段樹基本操作:

以下未做說明時:

l為區間左端點值,r為區間右端點值,rt為當前節點下標。x為查詢區間左端點,y為查詢區間右端點。

線段樹表示:

int sum[n<<2];

線段樹構建:

void build_tree(int l,int r,int rt) 

int m = (l + r) >> 1;

build_tree(lson);//遞迴處理左子樹

build_tree(rson);

sum[rt] = sum[lc] + sum[rc];//維護當前節點性質

}

線段樹更新:

void update(int p,int v,int l,int r,int rt)//將點p的值改變v 

int m = (l + r) >> 1;

if(p <= m)update(p,v,lson);

else update(p,v,rson);

//自頂向下更新,結束後維護性質

sum[rt] = sum[lc] + sum[rc];

}

線段樹查詢:

int query(int x,int y,int l,int r,int rt)

函式呼叫:

int main()

else if(cmd[0] == 'a')

else if(cmd[0] == 's')

else break;

} }return 0;

}

線段樹將大的區間進行二分,分為兩個較小的區間,在區間上儲存了足夠多的資訊來讓你維護區間性質。

能夠使用線段樹解決的問題應該滿足區間加法,即可以通過左右子樹的資訊維護當前節點的資訊。

包括但不限於區間求和,區間最值,求染色狀態,查詢區間和為指定值的段等。

例:hdu 1754(i hate it)點修改,查詢最大值

關鍵在於每次修改完成之後要保證整棵樹的性質。最大的話區間的最大一定是左子樹最大和右子樹最大取最大值,每次更新點之後要進行維護。

線段樹 01 線段樹基礎

物理上 public class segmenttree public int getsize public e get int index 返回完全二叉樹的陣列表示中,乙個索引所表示的元素的左孩子節點的索引 private int leftchild int index 返回完全二叉樹的陣列表示中...

線段樹 基礎

d 基礎 time limit 1000msmemory limit 32768kb64bit io format i64d i64u submit status description c國的死對頭a國這段時間正在進行軍事演習,所以c國間諜頭子derek和他手下tidy又開始忙乎了。a國在海岸線沿...

線段樹基礎

寫得不錯啊。前段時間寫了篇 搞懂樹狀陣列 如果說樹狀陣列是優雅的,那麼線段樹就是萬能的。有句話就叫 樹狀陣列能做的線段樹都能做,但是樹狀陣列能做的堅決用樹狀陣列!因為線段樹本來的內容狠豐富的,主要有單點跟新 區間跟新,最值詢問 區間詢問 反正就是對於區間進行的動態跟新詢問都能較高效的完成。對於初學者...