實際上還是稱為區間樹更好理解一些。
樹:是一棵樹,而且是一棵二叉樹。
線段:樹上的每個節點對應於乙個線段(還是叫「區間」更容易理解,區間的起點和終點通常為整數)
同一層的節點所代表的區間,相互不會重疊。同一層節點所代表的區間,加起來是個連續的區間。
葉子節點的區間是單位長度,不能再分了。
線段樹的深度不超過log2(n)+1(向上取整,n是根節點對應區間的長度)。
線段樹上,任意乙個區間被分解後得到的「終止節點」數目都是log(n)量級。
線段樹上更新葉子節點和進行區間分解時間複雜度都是o(log(n))的。
這些結論為線段樹能在o(log(n))的時間內完成插入資料,更新資料、查詢、統計等工作,提供了理論依據。
非葉子節點可以放和,最值,型別,狀態,空間容量(一般用於離散化之後)。
1.結構體定義
struct node
}node[max*3]; //max視情況而定
關於max,
有時需要進行離散化處理,一般是qsort後開乙個很大的陣列儲存i++,進行對映;
有時候可能並不是題目給的那個明顯的n,而是需要輸入update的個數; 例如杭電2795;
總而言之,這一切的目的都是把max減到最小;
2.建樹
void build(int i,int l,int r)
3.更新
void update(int i,int l,int r,int c)
{ if(node[i].left==l&&node[i].right==r)
node[i].w+=c;
if(node[i].mid()>=r) update(i*2,l,r,c);
else if(node[i].mid()
build和update以void格式時都有乙個回溯功能,可以用起來減少步驟;例如build用於區域求和;update用於區段的更新;
if(node[i+i].w&&node[i+i+1].w) node[i].w=1;
不要一更新就更新到葉子節點,那樣更新效率最壞就可能變成o(n)的了!有些甚至要把資訊全部累計在非葉子節點,最後從某個葉子節點返回上去進行統計;
4.查詢
int query(int i,int l,int r)
{ if(node[i].left==l&&node[i].right==r) return node[i].w;
if(node[i].mid()>=r) return query(i*2,l,r);
else if(node[i].mid()
有些關於先後問題例如排隊poj2828,覆蓋poj2825,可以先從後而前考慮,因為後面的都是可以確定的;
當給你的某個值n比較小的時候,可能是給你遍歷的可能性;
線段樹還有區間合併和lazy標記需要拓展。
當然很多難題關於線段樹和其他知識點(例如數論)的結合就只能憑能力了。
下面**有點資料還不錯。
線段樹小結
按照牛的部落格寫了幾道題,刷了一周效果不錯 1.複習鞏固了以前的知識 2.還有改正了一些寫線段樹毛病 3.改正了在弱資料的影響下的錯誤方法ac的題目 4.還學到了線段樹新的型別題 總體效果不錯,總結一下 poj 2892 最直觀的是平衡樹,用樹狀陣列的findk的功能更酷一些,線段樹找第k小也可以,...
線段樹小結
線段樹是一顆二叉樹,每乙個結點維護一段區間。因為是二叉樹,所以可以用p 2表示p的左兒子,p 2 1表示p的右兒子。struct node t maxn 2 線段樹要開四倍空間給定長度為n的陣列a 下標從1開始 對區間 1,n 上的值建一顆線段樹。define lson p 2 define rso...
線段樹小結
線段樹基本概念 線段樹結構 線段樹和區間 線段樹性質 向上取整 這樣在進行更新查詢操作的時候,操作的複雜度就可以為log n 量級 葉子節點的數目和根節點表示的區間長度相同 若葉子節點的數目為n,則線段樹的總節點數目為2 n 1。因為線段樹的節點要麼是0度,要麼為2度,根據二叉樹的性質可知。線段樹操...