訓練了三周線段樹,對線段樹的點操作、斷更新和常見應用範圍進行總結,並記錄一些技巧。
線段樹是一種二叉搜尋樹,也是一顆平衡樹。樸素的遞迴寫法是對於每乙個非葉子節點[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國在海岸線沿...
線段樹基礎
寫得不錯啊。前段時間寫了篇 搞懂樹狀陣列 如果說樹狀陣列是優雅的,那麼線段樹就是萬能的。有句話就叫 樹狀陣列能做的線段樹都能做,但是樹狀陣列能做的堅決用樹狀陣列!因為線段樹本來的內容狠豐富的,主要有單點跟新 區間跟新,最值詢問 區間詢問 反正就是對於區間進行的動態跟新詢問都能較高效的完成。對於初學者...