摘自《演算法競賽高階指南》。線段樹是一種基於分治思想的二叉樹結構,用於在區間上進行資訊統計。
線段樹的基本特徵:
1.線段樹的每個節點都代表乙個區間。
2.線段樹具有唯一的根節點,代表的區間是整個統計範圍,如[1,n]。
3.線段樹的每個葉節點都代表乙個長度為1的元區間[x,x]。
4.對於每個內部節點[l,r],它的左子節點是[l,mid],右子節點是[mid+1,r],其中mid=(l+r)/2(向下取整)。
線段樹的節點編號方法:「父子二倍」節點編號法
1.根節點編號為1。
2.編號為x的節點的左子節點的編號為x*2,右子節點編號為x*2+1。
注意:儲存線段樹的陣列長度要不小於4n才能保證不會越界。(n為葉節點數)
structsegmentreet[n*4];//
struct陣列儲存線段樹
void build(int p,int l,int
r)//
葉節點
int mid=(l+r)/2;//
折半 build(p*2,l,mid);//
左子節點[l,mid],編號p*2
build(p*2+1,mid+1,r);//
右子節點[mid+1,r],編號p*2+1
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);//
從下往上傳遞資訊
} build(
1,1,n);//
呼叫入口
void change(int p,int x,intv)//
找到葉子結點
int mid=(t[p].l+t[p].r)/2
;
if(x<=mid)change(p*2,x,v);//
x屬於左半區間
else change(p*2+1,x,v);//
x屬於右半區間
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);//
從下往上更新資訊
} change(
1,x,v);//
呼叫入口
從根節點開始,遞迴執行以下過程:
1.若[l,r]完全覆蓋了當前節點代表的區間,則立即回溯,並且該節點的dat值為候選答案。
2.若左子節點與[l,r]有重疊部分,則遞迴訪問左子節點。
3.若右子節點與[l,r]有重疊部分,則遞迴訪問右子節點。
int ask(int p,int l,intr) cout
<1,l,r)呼叫入口
【例題1】:你能回答這些問題嗎
【例題2】:區間最大公約數
我們在修改指令時,可以在l≤pl≤pl≤r的情況下立即返回,只不過在回溯之前向節點p增加標記,標識「該節點曾經被修改,但其子節點尚未被更新」。
在後續的指令中,需要從節點p向下遞迴,我們再檢查p是否具有標記。若有標記,就根據標記資訊更新p的兩個子節點,同時為p的兩個子節點增加標記,然後清除p的標記。
這樣一來,每條修改的指令的時間複雜度從o(n)降到了o(log n)。
【例題】:乙個簡單的整數問題
主要**如下:
#define 100000+10struct
n segmenttreetree[n*4
];int
a[n],n,m;
void build(int p,int l,int
r)
int mid=(l+r)/2
; build(p*2
,l,mid);
build(p*2+1,mid+1
,r);
sum(p)=sum(p*2)+sum(p*2+1
);}
void spread(intp)}
void change(int p,int l,int r,int
d) spread(p);
//下傳延遲標記
int mid=(l(p)+r(p))/2
;
if(l<=mid)change(p*2
,l,r,d);
if(r>mid)change(p*2+1
,l,r,d);
sum(p)=sum(p*2)+sum(p*2+1);}
long
long ask(int p,int l,int
r)int
main()
else cout<1
,l,r);
}}
【例題1】:亞特蘭蒂斯
【例題2】:窗內的星星
資料結構 線段樹
啦啦啦啦啦啦線段樹是個好東西 好吧並沒有什麼好的 但貌似還是很好啊 線段樹就是一棵樹!顧名思義 又是這個詞 就是求關於一段的某些什麼什麼東西。比如區間最大值啊什麼的。引用百科知識 線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。對於線段樹中...
資料結構 線段樹
一 目標 1.如何快速的查詢出下列陣列arr 2,5 的和 2。以及更新arr 4 為6。用普通的方法查詢的複雜度為o n 更新的複雜度為o 1 這時候我們可以用線段樹來快速完成這些操作,複雜度為logn。二 內容 如何建立,查詢,更新線段樹。public class qurqpd int tree...
資料結構 線段樹
線段樹是一顆平衡的二叉搜尋樹,他以空間換區時間,讓線性查詢加速log級別的查詢,用到的演算法主要是二分搜尋和遞迴。例如 有陣列data 我有乙個需求,我需要頻繁的查詢區間i j的sum和。這裡先給出兩個解決方案 如果使用最普通的演算法遍歷,那麼查詢和更新的複雜度為o n 當然你還可以使用動態規劃,定...