淺究下 zkw 線段樹

遞歸式線段樹和 zkw 線段樹一樣, 都使用滿二叉樹, 常規的理解下遞歸式線段樹使用的只是滿二叉樹常用的的節點編號規則(堆式編號,下面的所有滿二叉樹同樣使用堆式編號),其本質是一個分治算法,並不使用完整的滿二叉樹;zkw 線段樹則使用了更多滿二叉樹的結構性質, 在遞歸式線段樹上難以使用 zkw 線段樹的算法。

以下介紹 zkw 線段樹。

和遞歸式線段樹一樣, 單位長度的區間由葉子節點代表。對於滿二叉樹, 其節點的標號是很有規律的, 如果將整顆滿二叉樹用作線段樹,那麼對於一顆深度爲 \(N\) ,根節點深度爲 0 的滿二叉樹, 對於一個單位區間 \([l,l]\), 其在滿二叉樹中對應的節點的編號爲 \(l+2^N-1\) 。另外, 對於同一深度的節點們, 其編號在值域上是連續的。

線段樹的一個精髓是對合法長度內任意長度的區間的拆分:多個葉節點被其公共祖先代表, 使得被拆分的區間拆分成 \(O(\log (序列長度))\)線段樹內的 區間。對於 zkw 線段樹也是如此,樸素的算法即:將被拆分區間拆成滿二叉樹上的代表單位區間的節點,標記其, 之後不斷迭代, 去掉擁有同一父親的兩個被標記節點的標記,並標記它們的父親, 迭代無法進行時被標記的所有節點所對應的區間即是此次拆分的結果。

當然樸素算法並沒有用到什麼性質。有幾個顯然的性質:

  1. 當前輪迭代未被清除的標記以後也不會被清除
  2. 每輪迭代後新被打上標記的節點的標號在值域上是連續的
  3. 設此輪迭代開始時最晚被打上標記的節點的標號區間是 [l,r], 則此輪迭代中不被清除標記的節點只能是 l 同或 r(同或與異或相對)。而標記不被清除的原因也很顯然:l 是其父親的右兒子, r 是其父親的左兒子。這個規則在 l,r 相等即極限情況下也是有效的。

所以拆分區間的算法可以轉化爲維護 l,r 的算法。l,r 可能的變換如下: l=l/2 or l=l/2+1r=r/2 or r=r/2-1。實際上,節點標號的奇偶性是區分節點是其父親的左節點還是右節點的一個簡單方法:偶數是左節點,奇數是右節點。由此對於 l, l 爲偶數時變換爲 l/2, 反之變換爲 l/2+1, r 相似。常用的寫法是維護 l-1 和 r+1, 變換時直接除以 2,可以輕鬆的證明是正確的。(這個構造真的妙

所以把要維護的區間平移一下就可以愉快地寫出單點加區間求和的程序了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章