標籤:os 資料 ar 問題 時間 log ef 不同的
動態樹
動態樹問題, 即要求我們維護一個由若干棵子結點無序的有根樹組成的森林。
要求這個資料結構支援對樹的分割、合并,對某個點到它的根的路徑的某些操作,以及對某個點的子樹進行的某些操作。
在這裡我們考慮一個簡化的動態樹問題,它只包含對樹的形態的操作和對某個點到根的路徑的操作:
維護一個資料結構,支援以下操作:
• MAKE TREE() — 建立一棵只有一個結點的樹。
• CUT(v) — 刪除 v 與它的父親結點 parent(v) 的邊,相當於將點 v 的子樹分離了出來。
• JOIN(v,w) — 讓 v 成為 w 的新的兒子。其中 v 是一棵樹的根結點,並且 v 和 w 是不同的兩棵樹中的結點。
• FIND ROOT(v) — 返回 v 所在的樹的根結點。搞清了這個問題,我們也容易擴充這個資料結構,維護每個點到它所屬的樹的根結點的路徑的一些資訊,例如權和、邊權的最大值、路徑長度等。
Link-Cut Trees
Link-Cut Trees 是由 Sleator 和 Tarjan 發明的解決這類動態樹問題的一種資料結構。
這個資料結構可以在均攤 O(logn) 的時間內實現上述動態樹問題的每個操作。
如果沒有用對樹的形態的改變的話,我們可以用樹鏈剖分,把樹剖分成許多條鏈並維護上面的權值資訊。
然而對於樹的形態的改變,樹鏈的剖分方案也要改變,我們藉助 Splay 的思想來動態維護許多樹鏈(稱為 Link-Cut Trees)。
Link-Cut Trees 的定義
稱一個點被訪問過,如果剛剛執行了對這個點的 ACCESS 操作。如果結點 v 的子樹中,最後被訪問的結點在子樹 w 中,這裡 w 是 v 的兒子, 那麼就稱 w 是 v 的 Preferred Child。如果最後被訪問過的結點就是 v 本身,那麼它沒有 Preferred Child。每個點到它的 Preferred Child 的邊稱作 Preferred Edge。由 Preferred Edge 串連成的不可再延伸的路徑稱為 Preferred Path。這樣,整棵樹就被劃分成了若干條 Preferred Path。對每條 Preferred Path,用這條路上的點的深度作為關鍵字,用一棵平衡樹來維護它(在這棵平衡樹中,每個點的左子樹中的點,都在 Preferred Path 中這個點的上方;右子樹中的點,都在 Preferred Path 中這個點的下方)。需要注意的是,這種平衡樹必須支援分離與 合并。這裡,我們選擇 Splay Tree 作為這個平衡樹的資料結構。我們把這棵平衡樹稱為一棵 Auxiliary Tree。知道了樹 T 分解成的這若干條 Preferred Path,我們只需要再知道這些路徑之間的串連關係,就可以表示出這棵樹 T。用 Path Parent 來記錄每棵 Auxiliary Tree 對應的 Preferred Path 中的最高點的父親結點,如果這個 Preferred Path 的最高點就是根結點,那麼令這棵 Auxiliary Tree 的 Path Parent 為 null。Link-Cut Trees 就是將要維護的森林中的每棵樹 T 表示為若干個 Auxiliary Tree。並通過 Path Parent 將這些 Auxiliary Tree 串連起來的資料結構。
實際上,對於定義要從兩方面去理解:
首先是邏輯結構,存在著一棵或多棵樹,這是在邏輯上存在的,我們要做的就是對這個森林進行操作與維護;
其次是物理結構,我們並沒有直接儲存這些樹,而是把樹剖分成了多條鏈,每條鏈作為一棵 Splay。Splay 中的最小結點就是鏈的頭結點。
回顧一下定義:
ACCESS(訪問):又叫 Expose,對結點的訪問操作。
Preferred Child(最佳孩子):最近一次訪問過的兒子。最近一次被訪問過的結點沒有 Preferred Child。
Preferred Edge(最佳邊):每個結點到 Preferred Child 的邊。
Preferred Path(最佳路徑):連續的 Preferred Edge 組成的邊。
Auxiliary Tree(輔助樹):在 Splay 上維護一條鏈,對於 Splay 上的每個結點,它的左子樹上的點都在鏈的上方,右子樹的點都在鏈的下方。
Path Parent(路徑的父親):記錄鏈上最高結點的父親,也就是 Splay 最左邊結點的父親,用於表示鏈與鏈之間的關係。
Link-Cut Trees 的操作Access
ACCESS 操作是 Link-Cut Trees 的所有操作的基礎。假設調用了過程 ACCESS(v),那麼從點 v 到根結點的路徑就成為一條新的 Preferred Path。如果路徑上經過的某個結點 u 並不是它的父親 parent(u) 的 Preferred Child,那麼由於 parent(u) 的 Preferred Child 會變為 u,原本包含 parent(u) 的 Preferred Path 將不再包含結點 parent(u) 及其之上的部分。
也就是說,過程 ACCESS 會改變邏輯上的樹上的鏈剖分,它將結點 v 到根結點的路徑作為一條新的鏈。而這條鏈會把舊的鏈切割開。
在物理上的 Splay 的表現就是,Splay 中的一些樹被斷開與重組。