This action might not be possible to undo. Are you sure you want to continue?

# Chapter 17

**Appendix: Splay trees and link-cut trees
**

17.1 Binary Search Trees

A binary search tree (BST) is a rooted binary tree in which each nonroot node x is designated as either its parent’s left child or its parent’s right child. (Each node has at most one left child and at most one right child.) Such a tree T deﬁnes a total order on its vertices, called BST order (or symmetric order). Intuitively, the order is left-to-right. Formally, we inductively deﬁne BST order as follows. The BST sequence for an empty tree is the empty sequence. For a nonempty tree T , the BST sequence consists of the BST sequence of the left subtree of T (if there is such a subtree) followed by the root of T followed by the BST sequence of the right subtree (if there is such a subtree). BSTs are often presented as data structures for representing dictionaries, but they are also useful for representing sequences and, more speciﬁcally, orderings. To represent an ordering σ of some ﬁnite set S , we use a BST whose vertices are the elements of S ; the BST order gives the ordering σ . The non-uniqueness of the representation turns out to be very useful. This is a recurring theme in computer science. A BST can be implemented using three mappings from S to S : parent(·), left(·), and right(·). Often it is useful to represent an assignment w(·) of weights to the elements of S . The next section introduces a useful way to represent such an assignment.

17.1.1

Delta Representation of weights

Rather than store explicit values at each node representing the item’s weight, we can use an implicit representation. We represent the weight of node u by storing the diﬀerence ∆w(u) between the node’s weight and that of its parent. 165

166 CHAPTER 17. APPENDIX: SPLAY TREES AND LINK-CUT TREES If the node is the root then ∆w(u) is assigned the weight of u itself. Thus the following invariant holds: Delta invariant: For each node u, w(u) = the ancestors of u.

v

∆w(v ), where the sum is over

Refer to Figure 17.1 for an example. This representation allows us to eﬃciently perform an operation that adds to the weights of many vertices at a time. To add β to the weights of all the descendants of a node v , add β to ∆w(v ).

E w=7 !w = 2 F w=5 !w = 5 G w=7 !w = 3 H w=4 !w = -1 I w=5 !w = 4 w=1 !w = -3

D B w=8 !w = 2

w=6 !w = -1 C

A

w=9 !w = 3

Figure 17.1: A BST with node-weights. The weight of each node is indicated by w. The diﬀerence between w for a node and w for its parent is indicated by ∆w. Note that, for each node, w for that node can be computed by summing ∆w over all the ancestors of that node. We use the term decoration to refer to additional ﬁeld associated with each node.

17.1.2

Supporting searches for small weight

We can augment the BST to support queries such as this: SearchLeftmost(λ): What is the leftmost element x in σ whose weight w(x) is no more than λ? To support such queries, we deﬁne minw(·) so that, for each node v , minw(v ) is the minimum weight assigned to a descendant of v . Note that, for a node v with children v1 , . . . , vk (k ≤ 2), minw(v ) = min{w(v ), min minw(vi )}

i

(17.1)

This equation will be useful in updating minw(v ) when v ’s children change.

BINARY SEARCH TREES E w=5 minw = 1 G w=4 minw = 1 I w=1 minw = 1 167 D w=7 minw = 6 B w=6 minw = 6 C F w=7 minw = 7 H A w=8 minw = 8 w=9 minw = 9 w=5 minw = 5 Figure 17. Now we derive the rule for the update. minw(uk ) − w(u)} min{0. .1. . .1.1.3 Delta Representation of min-weights The implicit representation of minw(·) builds on the implicit representation of w(·). minw(u) ∆minw(u) = = = = = min{w(u). Altering the structure of a BST in such a way as to change the descendants of u changes minw(u). Let w ˆ be the weight of the parent of u. in our representation of a sequence σ using a BST. ∆minw(u1 ) + ∆w(u1 ). minw(uk )} minw(u) − w(u) min{w(u) − w(u).1.1. When we add β to the weights of descendants of u by adding β to w(u). .3. (∆minw(uk ) + w(uk )) − w(u)} (17. . ∆minw(uk ) + ∆w(uk )} min{0. minw(u) = ∆minw(u) + w ( u) Refer to Figure 17. (∆minw(u1 ) + w(u1 )) − w(u). . uk be the children of u. . . . . . . 17. or zero if u has no parent.2: The weight of each node is indicated by w.4 Delta representation of left-right Suppose that. minw(u1 ). . . We label the vertices using ∆minw(·) so that the following invariant is satisﬁed: Delta min invariant: For each node u. so ∆minw(u) must be updated. Problem 17. .2) 17. Let u1 . minw(u1 ) − w(u). . . Write pseudocode in terms of minw(·) for SearchLeftmost(λ). we wish to quickly reverse the consecutive subsequence induced by the descendants of a . . The time required should be proportional to the depth of the tree. . The minimum weight of the subtree rooted at a node is indicated by minw. .17. the Delta min invariant is automatically maintained.

We wish to modify this sequence by reversing the subsequence F GHI .168 CHAPTER 17.2 and 17. if y has no parent). node. The diﬀerence bewteeen minw and w for a node is indicated by ∆minw. let b be the root of the subtree labeled B .3: The minimum weight of the subtree rooted at a node is indicated by minw. APPENDIX: SPLAY TREES AND LINK-CUT TREES minw = 1 w=5 !minw=-4 G minw=1 w=4 !minw=-3 I minw=1 w=1 !minw=0 E D minw=6 w=7 !minw=-1 B A minw=8 w=8 !minw=0 minw=6 w=6 !minw=0 F minw=7 w=7 !minw=0 C minw=9 w=9 !minw=0 H minw=5 w=5 !minw=0 Figure 17.6 Updating Delta representations in a rotation Since Delta representations depend on the structure of a BST. Instead of explicitly representing ﬂipped(v ) at each node. Therefore for each node v the value of ﬂipped(v ) is the sum of ∆ﬂipped(x) over all ancestors x of v .4. 17. Rotation preserves the BST order. To reverse the order among the descendants of a node v . 17. which is deﬁned as ﬂipped(v ) − ﬂipped(parent(v )) where the subtraction is mod 2. we explicitly represent ∆ﬂipped(v ). obtaining ABCDEIHGF . For example. indexed by 0 and 1. For example.1. We will later describe a rule for carrying out rotations that enables us to get good time bounds for binary-tree operations. As shown there. See Figure 17. the BST in Figures 17. . To support such modiﬁcations.5 Rotation: An order-preserving structural change to a binary search tree A binary search tree can be structurally changed by rotating a node up in the tree. where the sum is mod 2. A binary value ﬂipped associated with each node signiﬁes which element of the array gives the left child of that node.1. we add one (mod 2) to ∆ﬂipped(v ). for any node x in a BST there is a series of rotations that results in x being the root. Refer to Figure 17. these must be updated when a rotation takes place.1 represents the sequence ABCDEF GHI . The weight of each node is indicated by w.5. We associate with each node a two-element array. we use a delta representation of left and right. Let w ˆ be the weight of the parent of y (or zero.

w ( x) w (y ) w ( b) = = = ∆w ( x ) + w ˆ ∆w ( y ) + w ( x ) ∆w ( b) + w ( y ) . that the weight of the Using ∆w (·) to denote the values of the ∆w decorations in this tree.4: Starting with the tree on the left.1. w (y ) w ( x) w ( b) = = = ∆w ( y ) + w ˆ ∆w ( x ) + ∆ w ( y ) + w ˆ ∆w ( b) + w ( x ) Now consider the tree resulting from rotating x. BINARY SEARCH TREES y 169 x rotate x up x C rotate y up A y A B B C Figure 17. We have the following equations. The triangles represent subtrees that are not changed by the rotation. which appears on the right in Figure 17. rotating y up yields the tree on the left. Note that the parent of x in this tree is the parent of y in the tree on the left. we have the following equations.5: This ﬁgure helps us derive the rule for updating Delta representations in a rotation. rotating x up yields the tree on the right. Starting with the tree on the right.4. y x rotate x up x C b A b y A B B C Figure 17.17.

7 Updating ∆ min representations in a rotation The rotation changes the descendants of x and y . or if x is the right child of its parent and its parent is the right child of its grandparent. and each operation moves the node x closer to the root. we perform a zig operation. APPENDIX: SPLAY TREES AND LINK-CUT TREES We can use the equations to derive rules for updating the ∆w(·) decorations: ∆w ( x ) ∆w ( y ) ∆ w ( b) = = = = = = ∆w ( x ) + ∆ w ( y ) − ∆w ( x ) w ( y ) − w ( x) w ( x) − w ˆ w ( b) − w ( y ) ∆ w ( b) + ∆ w ( x ) leading to the update ∆w (x). Therefore. there is some freedom in selecting the rotations. Which operation should be applied depends on the relationship between x and its parent and grandparent (if they exist). we perform a zig-zig operation: ﬁrst rotate up the parent of x and then rotate up x.2 Splay trees In moving x to the root. Each rotation can be done in constant time.) • Suppose x has a grandparent. We deﬁne three operations performed on a node x in a BST.2. (See Figure 17.1. called splay operations. ∆w (b) = ∆w(x) + ∆w(y ).) . so we will obtain a time bound.6. −∆w(x).7. Moving a node x to the root following these rules is called splaying x to the root. 17. ∆w (y ). after the updates to ∆w(·) have been made. The splay tree data structure [Sleator and Tarjan.170 CHAPTER 17. 17. which simply rotates x up. We will prove a theorem that implies a bound on the total number of rotations required for many such splayings. Each splay operation consists of one or two rotations. are • If x has no grandparent and is the left child of its parent. ∆w(b) + ∆w(x) The same technique can be used for preserving ﬂipped(·). 1985] speciﬁes some rules for selecting these rotations so as to ensure that the time required is small. If x is the left child of its parent and its parent is the left child of its grandparent. (See Figure 17. if ∆ min(·) is being maintained then ∆minw(x) and ∆minw(y ) must be updated using Equation 17.

17.2. z z x rotate x up rotate x up A y A B x z y x y D B C A C D B C D Figure 17. SPLAY TREES y x 171 rotate x up x C A y A B B C Figure 17.2. (See Figure 17. the average time per operation is O(log n).7: The zig-zig step. we perform a zig-zag operation: ﬁrst rotate up x and then again rotate up x.8: The zig-zag step . • If x is the left child of its parent and its parent is the right child of its grandparent.1 Potential Functions for Amortized Analysis The analysis of splay trees will show that each operation takes amortized O(log n) time: over a sequence of many operations on the tree.17. Each individual operation can take O(n) time in the worst case.6: The zig step z rotate y up y x rotate x up y D x z A B y x z C A B C D A B C D Figure 17. or vice versa.8.) Splaying a node x to the root consists of repeatedly applying the applicable splay operation until x is the root.

Fact 17. Applying the deﬁnition of concavity with x = 2u. β ] −→ R is monotone nondecreasing if f (x) ≤ f (y ) for all x ≤ y. The virtual cost is the actual cost plus the change in potential: ∆Φ = Φ(after) − Φ(before). a little calculus shows that log x and x are monotone nondecreasing and concave. If the ﬁrst derivative of f is nonnegative then the function is monotone nondecreasing. If the second derivative of a function is nonpositive over some interval then the function is concave over that interval. we obtain log(2u) + log(2v ) ≤ log(u + v ) 2 Applying the deﬁnition of monotonicity with x = u + v and y = 1. √ For example.2. 17.172 CHAPTER 17. Therefore the total actual cost is bounded as actual cost = virtual costs + Φ(initially) − Φ(ﬁnally) ≤ virtual costs + Φ(initially) using the fact that Φ(ﬁnally) is nonnegative. v ≥ 0. u + v ≤ 1} ≤ −2 Proof. Summing the virtual costs over a (long) sequence of operations to the tree gives: virtual costs = actual cost + ∆Φ = actual costs + Φ(ﬁnally) − Φ(initially) where the last step is obtained by telescoping the sum ∆Φ.1. y = 2v .2 Analysis of splay trees A function f : [α.2. y ∈ [α. we obtain log(u + v ) ≤ log(1) .3. The actual cost of an operation is deﬁned so as to be a constant times the actual time required to perform the operation. Lemma 17. Φ is chosen in a way that it is bounded initially (by an amount that will be useful in the analysis of the running time) and always remains nonnegative. max{log u + log v : u. if the average of the images of x and y under f is at most the image of the average of x and y ). β ] −→ R is concave if f (x)+ ≤ f ( x+ 2 2 ) for all x. β ] (i.2. APPENDIX: SPLAY TREES AND LINK-CUT TREES To perform this analysis we will associate a potential Φ with the state of the current tree. Fact 17.2. f (y ) y A continuous function f : [α.e. Typically.2.

Deﬁne the virtual cost of a splay operation to be the actual cost plus the resulting change in the potential in the BST. and let D (v ) be the set of descendants in T .4. Deﬁne the potential of a BST T to be the sum of the ranks of its vertices. Lemma 17.2. Proof. zig: The virtual cost is given by: = ≤ ≤ 1 + r ( x) − r ( x) + r ( y ) − r ( y ) 1 + r ( x) − r ( x) 1 + 3(r (x) − r(x)) since r (y ) < r(y ) since r (x) > r(x) 1 + Φ(T ) − Φ(T ) zig-zig: The virtual cost is given by: = = ≤ 2 + r ( x) + r ( y ) + r ( z ) − r ( x) − r ( y ) − r ( z ) 2 + r (y ) + r (z ) − r(x) − r(y ) since r (x) = r(z ) 2 + r (x) + r (z ) − r(x) − r(x) since r (y ) ≤ r (x) and r(y ) ≥ r(x) ≤ ≤ ≥ ≥ 3(r (x) − r(x)) 2r (x) − r (z ) − r(x) − 2r ( x ) + r ( z ) + r ( x ) r ( x) − r ( x) + r ( z ) − r ( x) 2 + Φ(T ) − Φ(T ) The following inequalities are equivalent: ⇐⇒ ⇐⇒ ⇐⇒ 2 + r ( x) + r ( z ) − r ( x) − r ( x) 2 −2 −2 For a node v . Let T be a BST. Let T be the BST resulting from performing a single splay operation on x. If x has a grandparent. • If the operation was a zig. We denote the potential of T by Φ(T ). and let x be a nonroot node.2. the last inequality is equivalent to | D ( x) | |D (z )| −2 ≥ log + log | D ( x) | | D ( x) | . T ) by r (x). We denote the parent of x by y . 1 for a zig operation and 2 for a zig-zig operation and a zig-zag operation. we denote r(x. T ) by r(x) and r(x. the virtual cost is at most 3(r(x. T )).e. SPLAY TREES These two inequalities yield 2 + log u + log v ≤ 0 173 Deﬁne the rank of a node in a BST to be the base-2 logarithm of the number of descendants of that node. Deﬁne the actual cost of a splay operation to be the number of rotations it performs. For brevity. T ) − r(x. • Otherwise. T ) − r(x. let D(v ) be the set of descendants of v in T . T )). We denote the rank of x in T by r(x. i. By the deﬁnition of rank. we denote it by z . T ). the virtual cost of the operation is at most 1 + 3(r(x.17.

it is the last step. Proof. v. and let x be a nonroot node. For i = k .2. If there is any zig step. we infer that the total is 3(rk − r0 ) + 1. d(x ) d (z ) Lemma 17. v ]. the virtual cost is at most 3(ri − ri−1 ) + 1. The total virtual cost at most 3(r(x.2. Let T be a BST. . .5. 17. v ] whose weight is minimum. v ): ﬁnd the item in the substring σ [u. Using splay trees with Delta representations of w(·) and minw(·). in the data structure described in the next section. For i < k . This can already be used to show a bound of O(n log n) on the actual cost of n splay operations on trees over n elements. • AddToRange(u. . ||D (x)| + |D (x)| ≤ 1. . However.2. 1. let ri be the rank of x after i splay steps. the virtual cost of the ith splay step is at most 3(ri − ri−1 ). T )) + 1. β ): add β to the weight of all items in the substring σ [u.5. T ) − r(x. For i = 0. . k .3 therefore implies that log d + log d ≤ −2. Using telescoping sums. show how to represent a sequence σ of n items with associated weights such that the following operations are supported in O(log n) time. Corollary 17. Let T be the BST resulting from splaying x to the root. (x ) (x ) zig-zag: The virtual cost is given by: = = ≤ 2 + r ( x) + r ( y ) + r ( z ) − r ( x) − r ( y ) − r ( z ) 2 + r ( y ) + r ( z ) − r ( x) − r ( y ) since r (x) = r(z ) 2 + r (y ) + r (z ) − 2r(x) since r(y ) > r(x) ≤ ≤ ≥ ≥ 2(r (x) − r(x)) 2r (x) − r (y ) − r (z ) r ( y ) − r ( x) + r ( z ) − r ( x) d (x ) d (z ) log d (x) + log d (x) 2 + Φ(T ) − Φ(T ) ⇐⇒ ⇐⇒ ⇐⇒ 2 + r ( y ) + r ( z ) − 2r ( x ) 2 −2 −2 The last line is true by the same argument used for the zig-zig case.2.3 Using splay trees to represent sequences and trees Problem 17.6. • MinRange(u. Suppose k splay steps are required to splay x to the root.174 CHAPTER 17. we use the speciﬁc form of the bound stated in Corollary 17.2. APPENDIX: SPLAY TREES AND LINK-CUT TREES D ( x )| |D ( z ) | Since D(x) ∪ D (z ) ⊆ D (x) and D(x) ∩ D (z ) = ∅.

we discuss a data structure that supports some interesting tree operations (but is simpler than the data structure we describe in the next section). (Darts will come up often in the remainder of the book. We represent a rooted forest by a set of such splay trees. d2 ): add an edge e to the forest between the tail of dart d1 and the tail of dart d2 . Augment the data structure of Problem 17.2. A sequence corresponds in graph theory to a path. • Given elements x and y . there is a closed path that uses every dart exactly once.) Given any tree (indeed. Give pseudocode for each of the following operations. We need to represent rooted forests more generally.2.) We represent a tree by the sequence σ of darts.17. any connected graph). y ]. • remove(e): remove an edge e from the forest. REPRESENTATION OF LINK-CUT TREES 175 Problem 17. and we represent the sequence σ by a splay tree whose vertices are the darts. one for each tree.9.8): • getValue(e): return the label of the child endpoint of e. Describe a data structure for representing a sequence σ over S and an assignment of weights to the elements of S .3 Representation of link-cut trees As we have seen. (There might be many such paths. β ): add β to the label of every node in the subtree rooted at the child endpoint of e.8.2. • Given number λ. ﬁnd the leftmost element in σ whose weight is at most λ. one oriented in each direction. • add(e.3. where n = |S |: • Given elements x and y . y ]. The following operations should be supported in amortized O(log n) time per operation. reverse the substring σ [x. there are two darts. • add(e. Problem 17. d1 .2. In this problem.2. 17. • ancestor(e1 . add β to the elements of the substring σ [x. . 1983. and then show that the amortized time per operation is O(log n) where n is the maximum number of edges. We use the link-cut trees of [Sleator and Tarjan.8 to represent a labeling d(·) of the vertices by numbers so as to support the following operations (in addition to those speciﬁed in Problem 17. and a number β . e2 ): return true if the e1 -to-root path in the tree containing e1 contains e2 . Corresponding to each edge of a graph. Problem 17. splay trees can be used for representing sequences.7.

In preparation for the analysis of the expose operation.3.9. Each splice converts . A rooted tree is represented as a collection of paths joined together. The operation is illustrated in Figure 17. To choose a representation. we will designate each arc of the tree as either dashed or solid.9: A rooted tree divided into solid paths.1.3. Now we analyze the number of splices due to exposing u. APPENDIX: SPLAY TREES AND LINK-CUT TREES v Figure 17. We will make use of the operation of exposing a node u: Ensure that the solid path containing v contains all u’s ancestors by converting dashed arcs along the path to solid and solid arcs incident to the path to dashed.1 High-level analysis of the expose operation Splicing a dashed arc uv means converting uv to a solid arc and converting the other solid arc entering v (if there is one) to a dashed arc. Note that exposing u might leave u with a solid child edge. we deﬁne an arc from u to its parent v to be heavy if d(u) > 1 2 d(v ) and light otherwise. Deﬁne the actual cost of an expose operation to be the number of splices. An example is illustrated in Figure 17. Every node v has at most one heavy child arc and at most log n light ancestor arcs. The operation of exposing a node u can be performed by performing a series of splices and. See Figure 17. Lemma 17.176 CHAPTER 17. Sleator and Tarjan.10. 1985]. We will maintain the property that each node has at most one solid child-arc.11 for an illustration. 17. converting that arc to a dashed arc. if u has a solid child arc. The maximal paths consisting of solid arcs are called solid paths.

In this ﬁgure. Deﬁne ΦA (F ) = n − 1 − |{heavy solid arcs}|. Now we deﬁne the potential function. a dashed arc to solid. number of splices = = |{arcs converted from dashed to solid}| |{light dashed arcs converted to solid}| + |{heavy dashed arcs converted to solid}| (17.3. Let F denote a rooted forest in which each arc is designated either solid or dashed. Lemma 17. the number of splices plus the increase in Φ1 is at most 1 + 2 log n. When a node u is exposed.2. virtual cost = = ≤ = ≤ actual cost + increase in Φ1 number of splices + |{heavy solid arcs converted to dashed}| −|{heavy dashed arcs converted to solid}| −|{heavy dashed arcs converted to solid}| 2 log n by Lemma 17. at most log n splices convert a light dashed arc to solid. Proof.3) .10: An example of exposing a node u. REPRESENTATION OF LINK-CUT TREES 177 Expose(u) u u Figure 17.3.1 number of splices + |{light dashed arcs converted to solid}| 2 · |{light dashed arcs converted to solid}| by (17.17.3) By Lemma 17. the heavy solid path comprises u’s ancestors.3. The eﬀect is that the solid path containing u contains all of u’s ancestors.3. which we call ΦA .1.

we obtain Corollary 17.3 Link-cut trees that do not support descendant search In the implementation of link-cut trees that do not support descendant search or eversion. parent(v ) is y . 17. If v has a parent in B . For trees comprising n vertices.178 CHAPTER 17. and in the latter one searches the descendants.3. . If eversion is to be supported. Each solid path P in the abstract tree is represented in the concrete tree by a splay tree B over the vertices of P . For each node v in B . and right(v ). In the latter case. Another operation. as shown in Figure 17. There are two cases. whose BST order coincides with the rootward order of vertices in P . Let x be the rootmost end of P . In either case. In the former. eversion. The precise representations depends on which operations must be supported. We will use the term abstract tree to signify one of the trees represented by the data structure. For a node v in B . left(v ) points to v ’s left child in B (or has the value null if v has no left child).3. the children of v in B are called the solid children of v . either x has a parent y or x is the root. each node v has a pointer ﬁeld parent(v ) and a two-element array children[·] of pointers. Two categories of operations are ancestor search and descendant search. left(v ). Each node v has three pointer ﬁelds: parent(v ). eversion is supported using a Delta representation of left-right as described in Section 17. and similarly for right(v ). Next we specify the value of parent(v ) in the case when v is the root of its solid tree B . The non-solid descendants are those concrete descendants of v that are not in the same solid tree. each decomposed into solid paths. then parent(v ) points to the parent. so we will describe that one ﬁrst. The solid descendants of v are those concrete descendants of v that are in the same solid tree. allows one to change the root.1. APPENDIX: SPLAY TREES AND LINK-CUT TREES Now we analyze the actual costs. When we refer to a node’s parent/children/descendants/ancestors in the concrete tree. for at least n − 1 expose operations. as in concrete parent or concrete descendants. We will use the term concrete tree to signify a tree that the data structure uses. 17. and a Delta representation ∆ﬂipped(·) of left-right. the abstract tree is represented by a collection of splay trees that are linked together. Supporting descendant search involves introducing a new kind of node and an additional pointer per node. In the abstract tree.4. The simplest implementation is the one supporting neither descendant search nor eversion.3. one searches the ancestors of a given node v . the average number of splices per operation is at most 1 + 2 log n. Using the fact that the initial value of the potential function is at most n − 1.2 Representation of trees We will now describe how the data structure represents a forest of rooted trees.12.3. called a solid tree. In the former case. we will use the modiﬁer concrete. parent(x) is null.

each solid path in the abstract tree is represented in the concrete tree by a solid tree. Therefore x is neither left(y) nor right(y) even though parent(x) = y . although x is an (unacknowledged) child of y in the representing tree. We say in this case that x is a bastard unacknowledged child. To summarize. The code for Expose will not change. These subroutines are “hooks”. When a rotation takes place. We address this issue when discussing decorations. and each dashed arc xy is represented by an arc to y from the root of the solid tree containing x.3. For now.5. Note also that. one that works for link-cut trees not supporting descendant search. The code for Expose Step includes calls to two subroutines. • DashedToSolid(u. The node y might have many unacknowledged children. 17. decorations must be updated to preserve invariants. we will use a subroutine Expose Step that encapsulates the diﬀerences. and is also called directly in Expose. one that works for linkcut trees supporting descendant search. SolidToDashed and DashedToSolid: • SolidToDashed(v ) is called when v is the left child of the root. It is used in splaying. Question 17. x is not necessarily the child of y in the abstract tree.3. and is about to become an unacknowledged child. and left(y) and right(y) are determined by y ’s position in the corresponding solid tree. We will give one implementation for Expose Step now. 4 Expose Step(u)# move u’s parent to root of its solid tree . Later we will give another implementation for Expose Step.4 Implementing the expose operation for trees not supporting descendant search We give a procedure Expose that implements the expose operation. Write a procedure IsSolidRoot(v ) that returns true if v is the root of its solid tree. REPRESENTATION OF LINK-CUT TREES 179 Consider the former case. just assume that RotateUp(u) rotates u up as in Section 17. Note that y belongs to its own solid path in the abstract tree. def Expose(u): 1 splay u to the root of its solid tree 2 while u is not the root of the concrete tree. The procedure RotateUp(u) rotates u up. 3 # now u is at the root of its solid tree. and is about to become its left child.17. you can assume that they do nothing.1. We will use the same strategy to encapsulate code related to maintaining decoration invariants.4.3. Later we will give implementations that preserve invariants on decorations. v ) is called when u is an unacknowledged child of v . Since the implementation depends only in some details on whether the link-cut trees are to support descendant search. For now.

Recall that ΦA = n − 1 − |{heavy solid arcs}| is the potential function deﬁned in Section 17. and so do not aﬀect ΦC . one in Step 1 and one in each invocation of Expose Step. parent(u)) # u is about to become a solid child of parent(u) left(parent(u)) := u 17. and u is its left child splay parent(u) to root of its solid tree v := left(parent(u)) # v might be null if u = null.3.1 of the number of splices required when a node u is exposed. the virtual cost is the actual cost plus the increase in the potential function. Lemma 17. The call does • k +1 splayings. Consider a call to Expose(u). The splicings do not change the number of descendants of any node. Deﬁne ΦC = v r(v ) where r(v ) is the base-2 logarithm of the number of descendants of v in its concrete tree.3. Let u=v0 . which is why we use the subscript A. Deﬁne the overall potential function to be Φ = 2ΦA + ΦC . The splayings and the additional rotations do not change the abstract tree or its decomposition into heavy paths. each done in the last step of Expose Step. • k splicings. We use the subscript C to reﬂect the fact that ΦC depends on the concrete tree. As usual. . . Proof.3. We therefore deﬁne the actual cost of Expose(u) to be the number of rotations performed. and suppose it involves k iterations. The time required by a call to Expose is bounded by a constant times the number of rotations peformed. u is not root of its concrete tree post: u’s parent is root of its solid tree. vk be the vertices splayed to the roots of their solid trees.3. and let r (vi ) be its rank after the splaying.180 CHAPTER 17. APPENDIX: SPLAY TREES AND LINK-CUT TREES 5 RotateUp(u) def Expose Step(u): pre: u is root of its solid tree.1. . For each vi . and so do not aﬀect ΦA . .5 Analysis of Expose(u) for trees not supporting descendant search We combine the technique from splay-tree analysis with the analysis in Section 17. v1 . let r(vi ) be the rank of vi before it is splayed.5. . and • k additional rotations in Step 5 of Expose. The virtual cost with respect to Φ of Expose(u) is at most 3 + 8 log n. SolidToDashed(v ) # v is about to become an unacknowledged child of parent(u) DashedToSolid(u. Note that ΦA depends only on the abstract tree. v2 .

2. Let ri (u) be the rank of u after i iterations of Step 5. We refer to the original vertices of the concrete tree. for any n-node rooted binary tree T .17. As in the analysis of zig. . k − 1. By Lemma 17. We refer to these splay trees as dotted trees. . whether a solid node or a dotted node. which is bounded by k + log n.4) is bounded by k + 1 + 3(r (vk ) − r(v0 )) . if m ≥ n then the amortized actual cost per call is O(log n). The following problem shows that. Since a proliﬁc node might have many unacknowledged children (a common condition among celebrity vertices). as solid vertices.2. Thus the total virtual cost with respect to ΦC of Expose(u) is at most 2k + 1 + 4 log n. middle(v ) either points to a dotted node or is null. the ones representing vertices of the abstract tree. Hence the total virtual cost with respect to ΦC of these rotations is at most k + rk (u) − r0 (u). Since Φ is always nonnegative and never exceeds 2n + n log n. they are organized using a splay tree of auxiliary vertices. Each node v in the concrete tree. In the next section. In particular. LINK-CUT TREES THAT SUPPORT DESCENDANT SEARCH 181 By Corollary 17. Therefore the value of (17. If v is a dotted node.4) i=0 For i = 0. which in turn is bounded by k + 1 + 3 log n.4. In order to support descendant search. which shows r (vi ) < r(vi+1 ). just after the splaying of vi . with care. . Problem 17. middle(v ) points to a solid node. 17. the virtual cost with respect to ΦC of all the splayings is at most k 1 + 3(r (vi ) − r(vi )) (17. a node’s unacknowledged children must be partially acknowledged so that the tree search can descend from parent to an unacknowledged child. which in turn is at most 3 + 8 log n.6. there is a corresponding concrete tree for which ΦC ≤ dn. Consider the rotations in Step 5 of Expose. The number of descendants of vi+1 does not subsequently change until just before vi+1 is splayed. If v is a solid node. Show that there is a constant d such that.4 Link-cut trees that support descendant search This section needs more rewriting–it is a bit repetitive. one can ensure O(log n) actual cost per operation amortized over even fewer operations. the virtual cost with respect to ΦC of the ith rotation is at most 1 + ri (u) − ri−1 (u). 1 .3.3. . k + increase in ΦA ≤ 1 + 2 log n. we describe two additional operations and we show that each has virtual cost O(log n) as well. and to the vertices comprising them as dotted vertices. has one additional pointer. Therefore the total virtual cost with respect to Φ = 2ΦA + ΦC is at most 2(1 + 2 log n) + (1 + 4 log n). the number of descendants of vi is less than the number of descendants of vi+1 . the amortized actual cost per call of m calls to Expose is at most 3+8 log n +(2n + n log n)/m. middle(v ).5.

parent(v ) points to a solid node y . one per solid path of the abstract tree. v in diﬀerent trees such that u is the root of its tree. We can implement these operations using Expose(v ). . the solid vertices form splay trees. and GainParent. Furthermore. Write pseudocode for Expose Step(u) for trees with solid and dotted vertices. the solid path P is represented by a solid tree. • Link(u. and these splay trees are called solid trees. show that there is a constant d such that. and right(·) are used to represent these trees in the usual way.6 to handle the concrete representation that supports descendant search.182 CHAPTER 17.3. The pointers parent(·). called dotted trees. left(·). LoseRight. If v is the root of a dotted tree. there is a corresponding concrete tree consisting of solid and dotted vertices for which the value of the potential function is at most dn.4. The child u belongs to some solid path P .4. Extend the result in Problem 17. so the structure can be traversed top-down. The concrete parent of the root of that solid tree is not u (as before) but is instead a dotted node. for any n-node rooted binary tree T . that we will later use to preserve invariants on decorations: • LoseParent(v ) is called when v is the right child of the concrete root.1. Problem 17. a tree of solid vertices.5 Topological updates in link-cut trees Now we describe two operations that modify the structure of a tree: • Cut(u): given a node u that is not an abstract root. That is.2. just as before. v ): given two vertices u. 17. APPENDIX: SPLAY TREES AND LINK-CUT TREES As before. middle(v ) points to the root of this dotted tree. remove its parent edge from the forest. add the arc uv . Again we include “hooks” in the code. parent(v ) points to a dotted node (unless v is the root of the abstract tree. That dotted node belongs to a tree of dotted vertices (a dotted tree). Next. making u a child of v . in which case parent(v ) is null. making u a root. and the arc from v to its parent is about to be severed. analyze this variant: • Write the potential function. and the parent of the root of that dotted tree is v . • Show that the virtual cost of Expose is O(log n). If v is the root of a solid tree. The dotted vertices also form trees. Problem 17. however. In the concrete tree. LoseParent. Consider a dashed arc uv in the abstract tree. The dashed arcs in the abstract tree correspond to dotted vertices in the concrete tree. and each dotted node points to the root of the corresponding solid tree.

parent(right(u)) := null. u) is called when v and u are concrete roots and v is about to be made the right child of u. WEIGHT UPDATES FOR LINK-CUT TREES 183 • LoseRight(u) is called when u is the concrete root and is about to lose its right child. def Cut(u): pre: u is not the root of its abstract tree Expose(u) # u is root of its concrete tree. post: u is the child of v in their abstract tree.6 Weight updates for link-cut trees We now describe how to represent an assignment of weights to vertices so as to facilitate quickly updating the weights of many vertices at a time. This causes at most an increase of 1 in ΦA and can only decrease ΦC . and it has a right child LoseParent(right(u)) # right(u) is about to become root of its concrete tree LoseRight(u) # u is about to lose a child right(u).6. Therefore making v the right child of u increases the rank of v but of no other node. In each operation. the Expose operations have virtual cost O(log n).5. null def Link(u.1 Analysis of link and cut operations We consider the cost of the link and cut operations. which adds α to the weights of all the descendants of u. v ) pre: u is the root of its abstract tree. α). v 17. Thus the Cut operation has virtual cost O(log n). Thus the Link operation has virtual cost O(log n). u) # v is about to become the right child of u parent(v ).17. after the Expose operations. Cut removes a solid arc. right(u) := u. . • GainParent(v. 17. We consider two operations for such bulk updates: • AddToDescendants(u. Expose(u) # u has no right child Expose(v ) #v is a concrete root GainParent(v. u is the root of its concrete tree. In Link. This causes at most an increase of log n in ΦC and can only decrease ΦA .

we deﬁne GainParent and LoseParent as follows: def GainParent(v.4 don’t need to do anything since the invariant does not distinguish between acknowledged and unacknowledged children.184 CHAPTER 17.6. Instead.1. ∆w(u) += α if u has a right child. we avoid explicitly representing the weights. In each case. is about to be severed from parent ∆w(v )+ = ∆w(parent(v )) . To preserve the invariant during link and cut operations. we maintain the following invariant: The weight of a node u is the sum v ∆w(v ) over all ancestors v of u in the concrete tree. Each node v stores a weight increment ∆w(v ) such that the weight of a node equals the sum of the weight increments of some of its ancestors. u) pre: v and u are roots of their concrete trees v is about to be made the right child of u ∆ w ( v ) − = ∆w ( u ) def LoseParent(v ): # v is the right child of the concrete root. which adds α to the weights of all the ancestors of u. α). α): Expose(u) # The concrete descendants of u that are not concrete descendants of u’s right child are u’s abstract descendants. we use the Delta representation of weights described in Section 17. For each of the above operations.1 Supporting AddToDescendants To support AddToDescendants. 17. the rotation procedure RotateUp should be modiﬁed as in Section 17. APPENDIX: SPLAY TREES AND LINK-CUT TREES • AddToAncestors(u. AddToDescendants is implemented as follows: def AddToDescendants(u. ∆w(right(u)) −= α To preserve the invariant.6.3. The exact invariant satisﬁed by ∆w(·) depends on which bulk update is to be supported. Under this invariant.1. The “hook” subroutines SolidToDashed and DashedToSolid of Section 17.1. we show how to represent the weights so as to support the operation.

α): Expose(u) # The concrete descendants of u that are not concrete descendants # of u’s left child are u’s abstract ancestors. Under this invariant. α) would have had the eﬀect of adding α to the weights of descendants of proper ancestors of u. we deﬁne RotateUp. here the sum is restricted to solid ancestors. and subtracting α from ∆w(left(u)) compensates so as to not increase the weights of solid descendants that are not abstract ancestors.17.2 Supporting AddToAncestors To support AddToAncestors. we use a similar invariant: The weight of a node u is the sum v ∆w(v ) over all ancestors v of u in u’s solid tree. We therefore deﬁne procedures for the hooks SolidToDashed and DashedToSolid: def SolidToDashed(u): pre: u is solid child of root of concrete tree. Adding α to ∆w(u) increases by α the weight of all descendants of u in its solid tree. v ): pre: u is dashed child of v . AddToAncestors is implemented as follows: def AddToAncestors(u.1. adding α to ∆w(u) in AddToAncestors(u. we must take care to preserve the invariant when changing edges from solid to dashed and vice versa. Since the invariant distinguishes between solid children and unacknowledged children. so these ancestors of u are exactly the descendants of u in its solid tree that are not descendants of its left child (if it has one).6. This is why we needed to use a diﬀerent invariant. and LoseParent exactly as in Section 17. ∆w(left(u))− = α The step Expose(u) ensures that the solid path containing u contains all of u’s ancestors in the abstract tree. If we had used the same invariant as we used for AddToDescendants. about to become dashed child ∆w(u)+ = ∆w(parent(u)) and def DashedToSolid(u. Unlike the invariant for AddToDescendants. about to become solid child v is root of concrete tree ∆ w ( u ) − = ∆w ( v ) . To preserve the invariant.6. ∆w(u)+ = α if u has a left child. GainParent.6. WEIGHT UPDATES FOR LINK-CUT TREES 185 17.

3 Getting the weight of a node The following procedure returns the weight of a given node v : def GetWeight(v ): Expose(v ) return ∆w(v ) The correctness of this procedure uses the fact that. which has value either L (for leafmost) or R (for rootmost). α. APPENDIX: SPLAY TREES AND LINK-CUT TREES 17. • AncestorFindWeight(u. ∆w(v ) is its weight. A Delta representation of minw(·) is used. Make clear that We will see that each of the above search operations can be implemented dir=leafmost does not mean you have to prefer using one of the following two operations. To indicate which tiebreaking rule to use. dir): given a node u and a direction dir. • DescendantFindMin(u. and a direction dir. deﬁned for BSTs in Section 17. or null if there is no such descendant. once v is the root of its concrete tree. α. return the dirmost ancestor of u having weight at most α. We break ties by choosing the leafmost or rootmost among those vertices of minimum weight. we use a parameter dir. 17. dir): given a node u.1.186 CHAPTER 17. The invariant is Delta min invariant: For each node u. • AncestorFindMin(u. which are useful in their own right: deeper to less deep among ﬁnding a node having weight at most a given threshold: incomparable vertices.7 Weight searches in link-cut trees We now discuss how to provide support for searching a tree for a low-weight node. and a direction dir. One form of search is to ﬁnd a node with minimum weight among a set of vertices (descendants or ancestors). return the dirmost descendant of u having weight at most α. ﬁnd the dirmost minimum-weight ancestor of u in the conceptual tree. dir): given a node u. The key to supporting searches is maintaining a representation of minw(·).6. as described in Section 17. or null if there is no such ancestor. ﬁnd the dirmost minimum-weight descendant of u in the conceptual tree.3. a number α. Here we deﬁne minw(u) to be the minimum weight among solid descendants of u. minw(u) = ∆minw(u) + w ( u) . • DescendantFindWeight(u. dir): given a node u and a direction dir.2.1. a number α.

α. α is added to the weights of either all the descendants of u (in case of AddtoDescendants) or the solid descendants of u (in case of AddToAncestors). RotateUp(u) changes the children of two vertices. . By the Delta min invariant. α. . Link. dir) that takes as input a node u. ChildChange(u) must update ∆minw(u) based on the values of u1 . .6) def SolidFind(u. we use an auxiliary procedure SolidFind(u. L signiﬁes left and R signiﬁes right.8.17. so ChildChange must be called twice—ﬁrst for u’s former parent (now u’s child) and second for u. the precondition 17. right(u) if dir == left else right(u). 1 u1 . Therefore no change needs to be made to ∆minw(v ) for any node v .8 17. Let u be a node. • In bulk updates. doing so also adds α to the minw(·) values for the same set of vertices. The procedure returns the dirmost solid descendant v of u such that w(v ) ≤ α + w(u). .2. we need to add a call to a hook. ChildChange(·).8.5) and a direction dir (L or R). . uk as given in Equation 17. dir): pre: α ≥ ∆minw(u) post: Returns the dirmost solid descendant v such that w(x) ≤ α + w(u). the operation need not change ∆minw(u). left(u) 2 if u1 = null and α − ∆w(u1 ) ≥ ∆minw(u1 ). . SUPPORTING ANCESTOR SEARCHES 187 Under what circumstances must we update the ∆minw(·) label of a node? We ﬁrst note that no updates are needed if the structure of the concrete tree does not change: • The invariant makes clear that if an operation does not change the structure of the concrete tree. In order to maintain ∆minw(·). 17. AddToDescendants(u. and let its solid children be u1 . u2 := left(u).5 is equivalent to the condition α + w(u) ≥ minw(u) (17. The procedures that change the structure of the tree are RotateUp. . . α) or AddToAncestors(u. In each case. uk . . at the end of these three procedures.1 Supporting ancestor searches FindSolid For ancestor search. In this case. u and its former parent. α). and Cut. and does not change minw(u) or w(u). a number α such that α ≥ ∆minw(u) (17.

u1 has a solid descendant v of weight at most α + w(u). if neither Case 1 nor Case 2 holds then Case 3 must hold. right(u) if dir == left else right(u). It follows that the true running time is at most a constant times the actual cost. Moreover. The correctness of the procedure therefore follows by induction on the depth of recursion. By the Delta min invariant. α − ∆w(u1 ). u2 := left(u). By 17. α − ∆w(u2 ). We deﬁne the actual cost of the operation to be the actual cost of this splaying. the latter inequality holds if ∆minw(u1 ) + w(u1 ) ≤ alpha + w(u). so the condition in Step 4 tests whether this case holds. α. Now we consider the time required by the procedure. (Note that the procedure is tail-recursive. so ∆minw(u2 ) ≤ α − ∆w(u2 ). We know that the virtual cost of the splaying (and therefore of the whole procedure) is O(log n). dir) First we prove its correctness. u2 has a solid descendant v of weight at most α + w(u). so ∆minw(u2 ) + w(u2 ) ≤ α + w(u).6 (equivalent to the precondition) and the deﬁnition of min(u).2 AncestorFindWeight and AncestorFindMin Now we write AncestorFindWeight(u. . in case multiple descendants v satisfy the inequality. 17. Say a node is a candidate if it is an abstract ancestor whose weight is at most α. Finally. Case 1 holds if u1 = null and minw(u1 ) ≤ α + w(u). there exists a solid descendant v of u such that w(v ) ≤ α + w(u). the dirmost descendant is returned. 2. the weight of u itself is at most α + w(u). left(u) One of the following cases must hold: 1. dir). Therefore in this case the precondition for the recursive call in Step 7 is satisﬁed.188 CHAPTER 17. so can easily be implemented iteratively. APPENDIX: SPLAY TREES AND LINK-CUT TREES 3 4 5 6 7 return SolidFind(u1 . or 3. Case 2 holds if w(u) ≤ α + w(u). The condition in Step 2 therefore tests whether Case 1 holds.8. As in Step 1. which holds if ∆minw(u1 ) ≤ α − ∆w(u1 ). Note that. so minw(u2 ) ≤ α + w(u). dir) if α ≥ 0 splay u to the root of its solid tree return u return SolidFind(u2 . if that condition holds then the precondition for the recursive call in Step 3 is satisﬁed.) The depth of recursion equals the depth in in the solid tree of the node returned. deﬁne u1 . Recall that the goal is to return u’s dirmost abstract ancestor whose weight is at most α. the node returned is splayed to the root of its solid tree. In Step 5.

if there are no eligible descendants.8. the procedure returns u.4. we deﬁne m inw(x) to be the minimum weight among all concrete descendants of x. It does this by checking whether there are any vertices in the right subtree (right(u) = null) and. Argue that your procedure is correct. However. For each solid node u. α − ∆w(right(u)) − ∆w(u). in which case the procedure returns null). α.8. By the Delta min invariant.17. to facilitate searching among them. return null return SolidFind(right(u). Otherwise.1. Next the procedure checks whether the right subtree contains a candidate. def AncestorFindWeight(u. . we do need a decoration. Whether we use an explicit or Delta representation of m inw(·) depends on whether we need to support ancestor updates or descendant updates. Since u is the concrete root. they do not need ∆w(·) decorations. the value is ∞. the procedure uses SolidFind to ﬁnd the dirmost candidate in the right subtree (unless the right subtree has not candidate. If u is a candidate and either we seek the leftmost candidate or there are no candidates to the right. dir) Problem 17. Since they do not belong to solid trees. Since the dotted vertices do not have weights. return u if not candidate on right. we deﬁne m inw(u) to be the minimum weight among all concrete descendants of u that are not in the same solid tree as u. In either case. they do not need ∆minw(·) decorations. w(right(u)) = ∆w(right(u)) + ∆w(u). By the invariant for ∆w(·). 17. SUPPORTING ANCESTOR SEARCHES 189 First the procedure exposes u so that it is the concrete root. its weight is ∆w(u). whether minw(right(u)) ≤ α.8. For each dotted node x. Its ancestors consist of it and the descendants in its right subtree.3 Supporting descendant searches To support descendant searches. dir): Expose(u) u is candidate := ∆w(u) ≤ α candidate on right := right(u) = null and ∆minw(right(u)) + ∆w(right(u)) + ∆w(u) ≤ α if u is candidate and (dir==L or not candidate on right). Write the procedure AncestorFindMin in terms of SolidFind. we use dotted vertices as described in Section 17. The procedure next determines whether u itself is a candidate by checking whether its weight is at most α. minw(right(u) equals ∆minw(right(u)) + w(right(u)). so the procedure checks whether ∆minw(right(u) + ∆w(right(u)) + ∆w(u) ≤ α. if so.

m inw(middle(x)). Problem 17. m inw (right(x)). m inw(·) is represented explicitly as a decoration on each of the vertices. Clarify that Find can assume there is such a descendant. You can ·) is represented explicitly.8. for the dirmost descendant having weight at most a given amount. we update m inw(x) by m inw(x) := min{m inw (left(x)). For a node pointer p. we update m inw(u) by m inw(u) := min{m inw (left(u)). assume that minw( (·) for descendant searches with descendant upRepresenting minw dates To support descendant updates. These updates should be incorporated into ChildChange(·) for solid and dotted vertices. not just the solid descendants. Specify the given amount to be given explicitly or in terms of w(u) as in FindSolid? Maybe should be two mutually recursive procedures.2. Write a procedure Find. m inw (middle(u))} For a dotted node x.3. that searches among all the descendants of u. Each solid node u has a decoration ∆m inw(u) such that invariant for solid vertices: m Delta min inw(u) = ∆m inw(u) + w ( u) invariant for dotted vertices: m Delta min inw(x) = ∆m inw(x)+ w(u) where u is x’s closest solid ancestor ∗ ∗ ∗ ∗ ∗ Each dotted node x has a decoration ∆m inw(x) such that Need to discuss how to represent dart-weights with auxiliary vertices. You can assume ·) is represented explicitly.190 CHAPTER 17. including evert. deﬁne ∗ ∞ if p = null m inw (p) = minw(p) otherwise For a solid node u. Your search procedure will need to use that minw( both minw(·) and ∆ min(·). one for solid vertices and one for dashed. we use a Delta representation of m inw(·). Problem 17.8. m inw (right(u)). APPENDIX: SPLAY TREES AND LINK-CUT TREES (·) for descendant searches with ancestor updates Representing minw To support ancestor updates. Write DescendantFindMin in terms of Find. both solid and dotted. MORE DETAILS ARE NEEDED HERE . We describe how it can be updated when a node’s children change. ∆minw(middle(x))} Clarify interpretation of L/R for trees with middle children. analogous to SolidFind.

SUPPORTING ANCESTOR SEARCHES 191 .8.17.

It has one child in its solid path and three children not in its solid path. In the concrete tree in the right diagram. v has three unacknowledged children. The dotted lines between the vertices have arrowheads on both ends because these lines represent pointers in both directions. APPENDIX: SPLAY TREES AND LINK-CUT TREES Abstract tree Concrete tree Figure 17.3. The middle diagram shows a concrete tree with the structure described in Section 17. each of which in turn has as its middle node the root of a solid tree. On the right is the corresponding concrete tree.12: On the left is a diagram of an abstract tree. v has one middle child. Each solid node has a middle pointer that either is null or points to a dotted node.Consider the node v of the abstract tree. the root of a BST of dashed vertices. the root of a BST of dotted vertices. which are the roots of solid trees representing solid paths.192 CHAPTER 17. In the concrete tree in the middle diagram.13: This ﬁgure shows two concrete trees corresponding to the same abstract tree.3. v v v Abstract tree Concrete tree for ancestor search Concrete tree for descendent search Figure 17. a dotted node. . Each dotted node has a middle pointer that points to a solid node. The right diagram shows a concrete tree that supports descendant search.