Resilient Level Ancestor, Bottleneck, and Lowest Common Ancestor Queries in Dynamic Trees

We study the problem of designing a resilient data structure maintaining a tree under the Faulty-RAM model [Finocchi and Italiano, STOC’04] in which up to δ\documentclass[12pt]{minimal} \usepackage{amsmath} \usepackage{wasysym} \usepackage{amsfonts} \usepackage{amssymb} \usepackage{amsbsy} \usepackage{mathrsfs} \usepackage{upgreek} \setlength{\oddsidemargin}{-69pt} \begin{document}$$\delta $$\end{document} memory words can be corrupted by an adversary. Our data structure stores a rooted dynamic tree that can be updated via the addition of new leaves, requires linear size, and supports resilient (weighted) level ancestor queries, lowest common ancestor queries, and bottleneck vertex queries in O(δ)\documentclass[12pt]{minimal} \usepackage{amsmath} \usepackage{wasysym} \usepackage{amsfonts} \usepackage{amssymb} \usepackage{amsbsy} \usepackage{mathrsfs} \usepackage{upgreek} \setlength{\oddsidemargin}{-69pt} \begin{document}$$O(\delta )$$\end{document} worst-case time per operation.


Introduction
Due to a diverse spectrum of reasons, ranging from manufacturing defects to charge collection, the data stored in modern memories can sometimes face corruptions, a problem that is exacerbated by the recent growth in the amount of stored data.To make matters worse, even a single memory corruption can cause classical algorithms and data structures to fail catastrophically.One mitigation approach relies on low-level error-correcting schemes that transparently detect and correct such errors.These schemes however either require expensive hardware or employ space-consuming replication strategies.Another approach, which has recently received considerable attention [8,17,19,23,24,25,27], aims to design resilient algorithms and data structures that are able to remain operational even in the presence of memory faults, at least with respect to the set of uncorrupted values.
In this paper we consider the problem of designing resilient data structures that store a dynamic rooted tree T while answering several types of queries.More formally, we focus on maintaining a tree that initially consists of a single vertex (the root of the tree) and can be dynamically augmented via the AddLeaf(v) operation that appends a new leaf as a child of an existing vertex v. 1 It is possible to query T in order to obtain information about its current topology.We mainly concerned on the following well-known query types: (Weighted) Level Ancestor Queries: Given a vertex v and an integer k, the query LA (v, k) returns the k-parent of v, i.e., the vertex at distance k from v among the ancestors of v.In the weighted version of the problem each vertex of the tree T is associated with a small (polylogarithmic) positive integer weight, and a query needs to report the closest ancestor u of v such that the total weight of the path from v to u in T is at least k.Lowest Common Ancestor Queries: Given two vertices u, v, the query LCA(u, v) returns the vertex at maximum depth in T that is simultaneously and ancestor of both u and v. Bottleneck Queries: In this problem, each vertex has an associated integer weight and, given two vertices u, v, a BVQ(u, v) query reports the minimum/maximum-weight vertex in the path between u and v in T . 2 It is worth noticing that, when T is a path, the above problem can be seen as a dynamic version of the classical range minimum query problem.
In the range minimum query problem, a query RMQ(i, j) reports the minimum element between the i-th and the j-th element of a (static) input sequence [4].
For all of the above problems, linear-size non-resilient data structures supporting both the AddLeaf and the query operations in constant worst-case time are known [2,11].It is then natural to investigate what can be achieved for the above problem when the sought data structures are required to withstand memory faults.
To precisely capture the behaviour of resilient algorithms, one needs to employ a model of computation that takes into account potential memory corruptions.To this aim, we adopt the Faulty-RAM model introduced by Finocchi and Italiano in [19].This model is similar to the classical RAM model except that all but O(1) memory words can be subject to corruptions that alter theirs contents to an arbitrary value.The overall number of corruptions is upper bounded by a parameter δ and such corruptions are chosen in a worst-case fashion by a computationally unbounded adversary.
A simple error-correcting strategy based on replication provides a general scheme for obtaining resilient versions of any classical non-resilient data structure at a cost of a Θ(δ) blowup in both the time needed for each operation and the size of the data structure.This space overhead is undesirable, especially when δ can be large.For the above reason, the main goal in the area is obtaining compact solutions with a particular focus on linear-size data structures [8,16,17,18,19,23,24,27].However, for linear-size data structures, even δ = ω(1) corruptions can be already sufficient for the adversary to irreversibly corrupt some of the stored elements [16].The solution adopted in the literature is that of suitable relaxing the notion of correctness by only requiring queries to answer correctly with respect to the portions of the data structure that are uncorrupted.Notice that this is not easy to obtain since corruptions in unrelated parts of the data structure can still misguide the execution of a query (see [16] for a discussion). 3

Our results
We design a data structure maintaining a dynamic tree that can be updated via the addition of new leaves, and supports resilient (weighted) LA, LCA, and BVQ queries.
Our data structure stores each vertex of the current tree T in a single memory word of Θ(log n) bits.We will say that a vertex v is corrupted if the memory word associated with v has been modified by the adversary.A resilient query is required to correctly report The current tree T logically maintained by the data structure is depicted in (a).In this example, each vertex maintains a reference to its parent in T .In (b) some of the parent-child relationships have been altered by the adversary by corrupting the nodes highlighted in red.Since the algorithm cannot distinguish corrupted memory words from uncorrupted ones, its (defective) view of T is shown in (c).Nevertheless, a resilient data structure must still be able to correctly answer queries involving uncorrupted paths.For exampple, the query LA(v, k) is required to answer correctly for all (meaningful) values of k since the path from v to the root is uncorrupted, while query LA(w, k) is required to answer correctly for k ≤ 2. Since u is corrupted, the query LA(u, k) is allowed to answer incorrectly for every value of k.
the answer when no vertex in the tree path between the two vertices explicitly or implicitly defined by the query is corrupted.For example, a LA(v, k) query correctly reports the k-parent u of v whenever every vertex in the unique path from u to v in T is uncorrupted.
We deem our notion of resilient query to be quite natural since in any reasonable representation of T the adversary can locally corrupt the parent-children relationship and hence change the observed topology of T .See Figure 1 for an example.
Our data structure occupies linear (w.r.t. the current number of nodes) space, and supports the AddLeaf operation and LA, BVQ, and LCA queries in O(δ) worst-case time.For weighted LA queries, the above bound on the query time holds as long as δ = O(polylogn).
We point out that our solution is obtained through a general vertex-coloring scheme which is, in turn, used to "shrink" T down to a compact tree Q of size O(n/δ) that can be made resilient via replication.Each edge of Q represents a path of length δ between two consecutive colored nodes in T .If no corruption occurs, this coloring scheme is regular and will color all vertices having a depth that is a multiple of δ.While it is possible for corruptions to locally destroy the above pattern, our coloring is able to automatically recover as soon as we move away from the corrupted portions of the tree.We feel that such a scheme can be of independent interest as an useful tool to design other resilient data structures involving dynamic trees.
We leave the problem of understanding whether, similarly to other resilient data structures [16,24], one can prove a lower bound of Ω(δ) on the time needed to perform AddLeaf operation and/or to answer our queries.

Related work
Non-resilient data structures.Before discussing the known result in our faulty memory model, we fist give an overview of the closest related results in the fault-free case.Since the landscape of data structures that answer queries on dynamic trees is vast and diverse, we will focus only on the best-known data-structures capable of answering LA, BVQ, or LCA queries.
As far as LA queries are concerned, the problem has been first formalized in [5] and in [14].Both papers consider the case in which the tree T is static and show how to built, in linear-time, a data structure that requires linear space and that answers queries in constant worst-case time (albeit the hidden constant in [5] is quite large).A simple and elegant construction achieving the same (optimal) asymptotic bounds is given in [3].In [14], the dynamic version of the problem was also considered: the authors provide a data structure supporting both LA queries and the AddLeaf operation in constant amortized time.The best known dynamic data structure is the one of [2], which implements the above operations in constant worst-case time.This data structure also supports constant-time BVQ queries and constant-time weighted LA queries when the vertex weights are polylogarithmically bounded integers.Moreover, the solution of [2] also provides amortized bounds for the problem of maintaining a forest of n nodes under link operations (i.e., edge additions that connect two vertices in different trees of the forest) and LA queries.In this case, a sequence of m operations requires O(mα(m, n)) time, where α is the inverse Ackermann function.
Regarding BVQ queries with integer weights, in addition to the solution discussed above (which supports leaf additions and queries in constant-time), [7] shows how to also support leaf deletions using O(1) amortized time per update and constant worst-case query time.
The problem of answering LCA queries is a fundamental problem which has been introduced in [1].In [22], Harel and Tarjan show how to preprocess in linear time any static tree in order to to build a linear-space data structure that is able to answer LCA queries in O(1) time.The case of dynamic trees is also well-understood: it is possible to simultaneously support (i) insertions of leaves and internal nodes, (ii) deletion of leaves and internal nodes with a single child, and (iii) LA queries, in constant worst-case time per operation [11].

Resilient data structures.
As already mentioned, the Faulty-RAM model has been introduced in [19] and used in the context of resilient data structures in [17] where the authors focused on designing resilient dictionaries, i.e., dynamic sets that support insertions, deletions, and lookup of elements.Here the lookup operation is only required to answer correctly if either (i) the searched key k is in the dictionary and is uncorrupted, or (ii) k is not in the dictionary and no corrupted key equals k.The best-known (linear-size) resilient dictionary is provided in [8] and supports each operation in the optimal O(log n + δ) worst-case time, where n is the number of stored elements.The Faulty-RAM model has also been adopted in [24], where the authors design a (linear-size) resilient priority queue, i.e., a priority queue supporting two operations: insert (which adds a new element in the queue) and deletemin.
Here deletemin deletes and returns either the minimum uncorrupted value or one of the corrupted values.Each operation requires O(log n + δ) amortized time, while Ω(log n + δ) time is needed to answer an insert followed by a deletemin.
The Faulty-RAM model has also been adopted in the context of designing resilient algorithms.We refer the reader to [23] for a survey on this topic.
A resilient dictionary for a variant of the Faulty-RAM model in which the set of corruptible memory words is random (but still unknown to the algorithm) has been designed in [25].
In a broader sense, problems that involve non-reliable computation have received considerable attention in the literature, especially in the context of sorting and searching.See for example [9,10,13,15,20,21,26].

Structure of the paper
The paper is organized as follows.Section 2 introduces the used notation and formally defines the Faulty-RAM model.It also briefly describes the error-correcting replication strategy mentioned in the introduction.For technical convenience, in Section 3 and 4 we describe our data structure for LA queries only.This allows us to introduce all the ideas behind the more general coloring scheme discussed above.As a warm up, we first consider the simpler case in which the tree T is static and is already known at construction time (Section 3), and we then tackle the dynamic version of the problem (Section 4) for which we give our main result.In Section 5 we show how to modify our data structure to handle the other types of queries.

Preliminaries
Notation.Let T be a rooted tree.For each node v ∈ T , we denote with parent(v) the parent of v.If π is a path, we denote by |π| its length, i.e., the number of its edges.Given any two nodes u, v, we denote by d T (u, v) the length of the (unique) path between u and v in T .Moreover, if π traverses u and v, we denote by π[u : v] the subpath of π between u and v, endpoints included.We will use round brackets instead of square brackets to denote that the corresponding endpoint is excluded (so that, e.g., π(u : v] denotes the subpath of π between u and v where u is excluded and v is included).
Faulty memory model.We now formally describe the Faulty-RAM model introduced by Finocchi and Italiano in [19].In this model the memory is divided in two regions: a safe region with O(1) memory locations, whose locations are known to the algorithm designer, and the (unreliable) main memory.An adaptive adversary can perform up to δ corruptions, where a corruption consists in instantly modifying the content of a word from the main memory.The adversary knows the algorithm and the current contents of the memory, has an unbounded computational power, and can simultaneously perform one or more corruptions at any point in time.The safe region cannot be corrupted by the adversary and there is no error-detection mechanism that allows the algorithm to distinguish the corrupted memory locations from the uncorrupted ones.Without assuming the existence of O(1) words of safe memory, no reliable computation is possible: in particular, the safe memory can store the code of the algorithm itself, which otherwise could be corrupted by the adversary.
As observed in [16] (and already mentioned in the introduction), there is a simple strategy that allows any non-fault tolerant data structure on the RAM model to also work on the Faulty-RAM model, albeit with multiplicative Θ(δ) blow-up in its time and space complexities.Essentially, such a solution implements a trivial error-correcting mechanism by simulating each memory word w in the RAM model with a set W of 2δ + 1 memory words in the Faulty-RAM model: writing a value x to w means writing x to all words in W , and reading w means computing the majority value of the words in W (which can be done in O(δ) time, and O(1) space using the safe memory region and the Boyer-Moore majority vote algorithm [6]).We refer to such technique as the replication strategy.

Warming Up: LA queries in Static Trees
In order to introduce our ideas, in this section we will show how to build a simplified version of our resilient data structure when the tree T cannot be dynamically modified.Our simplified data structure requires linear space and answers level-ancestor queries in O(δ) time.As opposed to our dynamic data structure, in this special case the tree T must be known in advance and hence we need to initialize our data structure from an input tree T .For simplicity, we assume that no corruptions occur while our data structure is being built.Notice that this assumption can be removed by carefully using the replication strategy described in Section 2.
Algorithm 1 Answers a level ancestor query LA(v, k) in the special case of static trees.
2 Climb up the tree T from v for 2δ nodes searching a black node; 3 if the previous procedure did not find a black node then return error; 4 v ′ ← a black node found in the previous procedure; Description of the Data Structure.Let T be a rooted tree with n nodes.To define the data structure for T , we need to divide the nodes of T into two sets: the black nodes and the white nodes.We define the set of black nodes to ensure that its cardinality is O(n/δ): a node v in T is black if we simultaneously have that (i) its depth in T is a multiple of δ, and (ii) the subtree of T rooted in v has height at least δ − 1.A node v in T is white if it is not black.We notice that for each black v node in T there are at least δ distinct nodes (i.e., all the vertices in the path from v to any vertex having depth δ − 1 in the subtree of T rooted at v), thus implying that the total number of black nodes in T is at most n/δ.If we define a relation of parenthood for the black nodes of T , we can define a new black tree Q in which each vertex v is associated with black vertex v of T .The parent of v in Q is the vertex u corresponding to the lowest black proper ancestor u of v in T .See Figure 2 for an example.
Our data structure stores the (colored) tree T , as described in the following, along with an additional data structure D Q that is able to answer LA queries on Q.The tree T is stored as an array of records, where each record is associated with a vertex of T , occupies Θ(log n) bits, and is stored in a single memory word.The memory word associated with a node v stores: a pointer p v to parent(v), if any.If v is the root of T then p v = null; a pointer q v to the corresponding node v in Q, if any.If no such node exists, i.e. if v is white, then q v = null.
Moreover we maintain, for each vertex v of Q, a pointer to the corresponding vertex v of T as satellite data.The data structure D Q is the resilient version of any (non-resilient) data structure that is capable of answering LA queries on static trees in constant time and requires linear space (see, e.g., the data structure in [3]).
As we observed before, any data structure can be made resilient with a multiplicative Θ(δ) blow-up in its time and space complexities.In our case, since the number of vertices in

the query time becomes O(δ).
Notice that, in spite of the (at most δ) memory corruptions performed by the adversary, the data structure D Q always returns the correct answer to all possible LA queries on Q.We will denote by LA Q (v, k) the level-ancestor query on Q, which returns the vertex of T corresponding to the k-parent of v in Q.
The resilient level-ancestor query.In this section we show how to implement our resilient LA query.We start by defining a routine that will be useful in the sequel: if v is a node of T and i is a non-negative integer, we denote by climb(v, i) a procedure that returns the vertex reached by a walk on T that starts from v and iteratively moves to the parent of the current vertex i times.When the procedure encounters a vertex u with pointer p u = null that has

Figure 2
Left: A static tree T that has been colored according to the scheme in Section 3 for δ = 3. Right: the corresponding black tree Q.We also show the path climbed while answering the query LA(v, k) with k = 8.In this case d = 3, ⌊k ′ /δ⌋ = 1 and krest = 2. Notice how Q is used to quickly reach u ′ from v ′ .to be followed, climb(v, i) reports that the root has been reached.Notice that climb(v, i) requires O(i) time and, whenever no corrupted vertices are encountered during the walk, it correctly returns the i-parent of v.Although the climb(•, •) procedure could immediately be used to answer an LA query, doing so require Ω(n) time in the worst case.To improve the query time we use the data structure D Q described above and we distinguish between short and long LA(v, k) queries depending on the value of k.
Short queries, i.e., queries LA(v, k) with k ≤ 2δ, are handled by simply invoking climb(v, k) and, from the above observation, it follows that this is a resilient query.For longer queries the idea is that of locating a nearby black ancestor of v, performing an LA Q query on Q to quickly reach a black descendant u ′ of the k-parent w of v such that d(u ′ , w) ≤ δ, and finally using the climb procedure once more to reach w from u ′ .See Algorithm 1.
During the execution of our resilient query algorithm we always ensure that all followed pointers are valid.Since we are dealing with a static tree T , we can handle invalid pointers simply by halting the whole query procedure and reporting an error.A slightly more sophisticated handling of invalid pointers will be used to tackle the dynamic case.An example LA query is given in Figure 2.
The correctness of the above algorithm immediately follows from the fact that, when no vertex between v and the k-th ancestor v is corrupted, v must have a black ancestor at distance at most 2δ and from the fact that the replication strategy ensures that all queries on Q are always answered correctly. 4o show that Algorithm 1 answers an LA query in O(δ) time, we notice that the climb operations in lines 1 and 8 require time O(δ), and so does line 2.Moreover, the query to D Q (line 6) can also be performed in O(δ) time as discussed above.

LA queries in dynamic trees
In this section we provide our main result for LA queries.In Section 5, we show how our ideas can be extended to also handle weighted LA, BVQ, and LCA queries.

Description of the Data Structure
Some of the key ideas behind our data structure for LA queries in dynamic trees are extensions of the ones used for static case.Namely, the nodes of T are colored with either black or white, the set of black nodes will have size O(n/δ), and it will correspond to the vertex set of an auxiliary black forest Q. Ideally, in absence of corruptions, Q is exactly the black tree as defined in the static case, namely the tree in which the parent of each (black) node v in Q is the vertex u associated with the lowest black proper ancestor u of v in T .Moreover, we would still like the vertices of T having a depth that is a multiple of δ to be colored black, similarly to the static case.However, we can no longer afford to maintain such a rigid coloring scheme since the tree is now being dynamically constructed via successive AddLeaf operations, and the adversary's corruptions might cause vertices to become miscolored.We will however ensure that such a regular coloring pattern will be followed by the portions of T that are sufficiently distant from the adversary's corruptions.This will allow us to answer LA queries using a strategy similar to the one employed for the static case.
Our data structure stores the following information.The record of a node v maintains, in addition to the pointer p v to its parent and to the pointer q v to the corresponding node v in Q (if any), an additional field flag v .Intuitively, flag v can be thought of as a Boolean value in {⊥, ⊤}.The initial value of a flag is ⊥ and we say that the flag is unspent.Spending a flag means setting it to ⊤.We will spend these flags to "pay" for the creation of new black nodes.Spent flags will also signal the presence of a nearby black ancestor.
For technical reasons, we also allow an unspent flag flag v to be additionally annotated with a pair (x, i) where x is (the name of) a node and i is an integer.In practice this amounts to setting flag v to (x, i), which is logically interpreted as ⊥.Such an annotated flag is still unspent.This provides an additional safeguard against corruptions that may occur during the execution of our leaf insertion algorithm (see Section 4.2).
The node records are stored into a dynamic array A, whose current size n is kept in the safe region of memory.This array supports both elements insertions and random accesses in constant worst-case time. 5he pointer p v is then the index (in {0, . . ., n − 1}) of the record corresponding to the parent of v in A. Initially, A only contains the root r of T at index 0.Moreover, we will always store new leaves at the end of A so that, in absence of corruptions, the index of a vertex v in A is always smaller than the index of any of its descendants.As a consequence, whenever we observe the index stored in pointer p v is greater than or equal to the index of v itself, we know that v must have been corrupted by the adversary.We find convenient to use the above fact to simplify the handling of corrupted vertices: whenever we encounter an invalid pointer p v ≥ v we treat it as being equal to 0, i.e., an invalid pointer p v always refers to the root r of T .This rules also applies to any read pointer, including those accessed by the climb(•, •) procedure already defined in Section 3.
Then the (possibly corrupted) contents of A, at any point in time, induce a noisy tree T whose root is r, and the parent of each vertex v ̸ = r is the vertex pointed by p v according to the above rule.Clearly, if no corruptions occur T and T coincide.
Moreover, we store a resilient data structure D Q that, in addition to the already-defined LA Q (v, k) query, also supports the following additional operations in O(δ) time.NewTree Q (v): Given a vertex v of T , it creates a new tree in the forest Q consisting of a single vertex v associated to v, and it returns a pointer to v. AddLeaf Q (u, v): Given a vertex u of Q, and a vertex v of T , it creates a new vertex v associated to v as a children of u in Q.Finally, it returns a pointer to the newly added vertex v.
This data structure D Q is the resilient version, obtained using the replication strategy, of the linear-size data structure that supports both the AddLeaf operation and LA queries in constant time [2].Notice that D Q always returns the correct answer to all possible LA queries on Q.Moreover, once we ensure that the number of vertices that become black (and hence the size of Q) is always O(n/δ), we have that the (resilient) data structure D Q requires O(n) space (this will be shown formally in the proof Theorem 6).

The AddLeaf operation
Before describing our implementation of the AddLeaf operation, it is useful to give some additional definitions.We say that v is near-a-black in a tree T if there exists some k ∈ {1, 2, . . ., δ} such that the k-parent of v in T is black.Moreover, we say that The procedure AddLeaf(x par ) takes a vertex x par of T as input and adds a new child x of x par to T (see Algorithm 2).The record corresponding to new vertex x is appended at the end of the dynamic array A. For simplicity we will assume that, during the execution of AddLeaf(x par ), the record of vertex x is never corrupted by the adversary.This can be guaranteed without loss of generality since a (temporary) record for x can be kept in safe memory and copied back to A (which is stored in the unreliable main memory) at the end of the procedure.
Our algorithm consists of a first discovery phase and possibly of a second additional execution phase.The aim of the discovery phase is that of exploring the current tree by climbing up to 3δ − 1 levels of T from x while gathering information for the second phase.In order to do so, Algorithm 2 climbs δ levels of T from the newly inserted node x, reaching a vertex y, and checks during the process that all the flags associated with the traversed nodes are unspent.If any of these flags is spent, we immediately return from the AddLeaf(x par ) procedure without performing the execution phase.Otherwise, the algorithm climbs 2δ − 1 further levels from y to determine whether y appears to be black-free or near-a-black.In the latter case, it keeps track of the distance ℓ from y to the closest black proper ancestor y ′ of y that is encountered.If y is neither black-free nor near-a-black, we return from the AddLeaf(x par ) procedure (without performing the execution phase), otherwise we move on to the execution phase.A technical detail of the discovery phase is the following: while climbing from x par to y, the generic i-th unspent flag is annotated with (x, i) (possibly overwriting any existing previous annotation) and will be checked by the execution phase.Recall that these flags remain unspent.
The execution phase once again climbs δ levels of T staring from x, with the goal of changing the color of an existing white vertex to black (hence creating a corresponding black node in Q).This is guaranteed to happen unless the annotations of the unspent flags set during the discovery phase reveal that one such vertex has been corrupted in the meantime.The creation of a new black vertex in Q is "paid for" by spending these δ unspent flags (i.e., setting them to ⊤).The position of the new black vertex depends on whether y was  near-a-black or black-free.In the former case the vertex y ′ discovered in the first phase will be the δ-parent of the new black vertex x ′ , and a new leaf x ′ is appended to y ′ in Q.In the latter case, y will become black and a new tree containing a single vertex y is added to Q.
Notice that, if a vertex b is colored black during the AddLeaf operation, the execution phase always spends flag b .

Analysis of the data structure
In this section we analyze our data structure.The core of the analysis is to show that the AddLeaf operation in Algorithm 2 guarantees that in T , if we are sufficiently distant from all the corrupted vertices, the black nodes are regularly distributed.The formal property is stated in Lemma 5. We first need to prove auxiliary properties.In Figure 3 we give an example that shows that, even in an uncorrupted path, if we are not sufficiently distant from corruptions, the black nodes can form irregular patterns in the path.
The following lemma shows that if the flag of a vertex w appears to be spent, then either there must be a nearby black ancestor of w, unless a nearby corruption occurred.See Figure 4 (a).
▶ Lemma 1.Let w and z be two nodes such that z is the δ-parent of w in T and such that no node in the path π from z to w in T has been corrupted.If flag w = ⊤, then there exists a black node in π(z : w].
Proof.Let x be the node whose insertion in T caused flag w to be set to ⊤.Moreover, let P be the path of length δ from x to y traversed in the discovery phase of Algorithm 2 in lines 2-7.Similarly, let P ′ be the path from x to y traversed in the execution phase of Algorithm 2 in lines 18-24.
Clearly, P ′ contains w.Moreover, if w is the i-th node traversed in P ′ , then flag w = (x, i) in the execution phase and (since w is uncorrupted), flag w was set to (x, i) in the discovery phase.As a consequence, w is also the i-th node in P and P [y : w] = P ′ [y : w].Hence, y is at distance at most δ − 1 from w in P (and in T ) showing that z is a proper ancestor of y.Therefore all nodes in P ′ [y : w] are uncorrupted, and the loop in in lines 18-24 of Algorithm 2 is executed to completion.This ensures that the execution phase will color a node b black.We distinguish two cases depending on whether y was observed to be near-a-black or black-free in the discovery phase.
If y is black-free, then b is exactly y and the claim follows.Otherwise, y is near-a-black and the discovery phase computed the distance ℓ between x and its closest black proper ancestor.If ℓ ≥ i, then Algorithm 2 colors a vertex in P (z : w] = π(z : w] black.Otherwise, if ℓ < i, the discovery phase observed that the ℓ-parent y ′ of y was black.Since ℓ < δ, y ′ lies in π(z : y].◀ Next lemma shows that an uncorrupted path of length at least 3δ must contain a black vertex.▶ Lemma 2. Let x and z be nodes in T such that z is the 3δ-parent of x in T and such that no node in the path π from x to z in T has been corrupted.Then, there exists a black node w in π[z : x).
Proof.Since no vertex in π has been corrupted, the path π must also belong to the noisy tree T .In the rest of the proof we assume that π[z : x) contains no black nodes and show that this leads to a contradiction.
Let y the δ-parent of x in π and let t x be the time at which the AddLeaf(•) operation that adds x to T is invoked.We know that, at time t x , there exists no node w in π[y : x) such that flag w = ⊤ since otherwise Lemma 1 would immediately imply the existence of a black node in π[z : w] contradicting the initial assumption.Then, the invocation of Algorithm 2 that inserts x also performs its execution phase.
Moreover, y must be black-free at time t x , and hence it is colored black during such a phase (refer to the pseudocode of Algorithm 2, and recall that a black-free node is not near-a-black).Since y is not corrupted it must still be black, leading to a contradiction.◀ Recall that we would like each uncorrupted path to contain a black vertex every δ levels.Consider an uncorrupted path π of length between δ and 2δ with a single black vertex z on top.Then, the vertex at distance δ from z is "overdue" to become black.Next lemma shows that all flags associated with descendants of the overdue vertex in π must be unspent.In some sense, the data structure is preparing to recolor the missing black vertex.This will happen once δ unspent flags are available.See Figure 4 (b).
▶ Lemma 3. Let x and z be two nodes in T such that: z is an ancestor of x in T , no node in the path π from z to x in T has been corrupted, and δ ≤ |π| < 2δ.We have that, immediately after vertex x is inserted, if the only black vertex in π is z then all the nodes w in π at distance at least δ from z in T are such that flag w ̸ = ⊤.
Proof.Since no vertex in π has been corrupted, the path π must also belong to the noisy tree T .In what follows, we prove that, immediately after vertex x is inserted, the existence of a node w between x and z in π such that d T (w, z) ≥ δ and flag w = ⊤ leads to a contradiction.Indeed, since flag w = ⊤, Lemma 1 implies the existence of a black node in π(z : w], and this contradicts the fact that z is the only black node in π[z : x].◀ The next technical lemma is about the timing at which vertices of a long uncorrupted path become black.This will be instrumental to prove Lemma 5. See Figure 4 (c).
▶ Lemma 4. Let u and v be two nodes in T such that u is an ancestor of v, d T (u, v) ≥ 3δ and no node in the path π from v to u in T has been corrupted.Let y (resp.x) be the node in π at distance 2δ (resp.3δ) from u in π.Let t ′ v (resp.t ′ x ) be the time immediately after the vertex v (resp.x) is inserted.If the node y is black at time t ′ v , then there exists a node w ′ in π[y : x] that is black at time t ′ x .
Proof.Since no vertex in π has been corrupted, the path π must also belong to the noisy tree T .In the rest of the proof we assume towards a contradiction that y is black at time t ′ v , yet there are no black nodes in π[y : x] at time t ′ x .Let z be the δ-parent of y in π.Let t y be the time immediately before y is colored black.At time t y there are only two possible scenarios: Scenario 1: At time t y , the node y is black-free; Scenario 2: At time t y , the node z is the only black node in T in π[z : y].
We denote with t x the time immediately before vertex x is inserted in T and we consider the two scenarios separately (notice that t y refers to a later time than t x ).We split scenario 1 into two additional subcases: Subcase 1.1: at time t x all the nodes w in π[y : x) are such that flag w ̸ = ⊤; Subcase 1.2: at time t x there is a node w in π[y : x) such that flag w = ⊤.
We start considering subcase 1.1.Since t y follows t x , and y is black-free at time t y , vertex y must also be black-free at time t x .Then, during the insertion of x, Algorithm 2 colors y black yielding a contradiction.
We now analyze subcase 1.2.Since flag w = ⊤, Lemma 1 implies the existence of a black node b in π[w, z) and, since we assume that there are no black nodes in π[y : x], b is in π(z : y).This shows that y cannot be black-free at time t y and contradicts the hypothesis of scenario 1.1.
We now consider Scenario 2, which we subdivide into three subcases: Subcase 2.1.at time t x all the nodes w in π[y : x) are such that flag w ̸ = ⊤ and z is white; Subcase 2.2. at time t x all the nodes w in π[y : x) are such that flag w ̸ = ⊤ and z is black; Subcase 2.3.at time t x there is a node w in π[y : x) such that flag w = ⊤.
We start by handling subcase 2.1.For the initial assumption, and for definition of this case, we have that there are no black nodes in π[z : x] at time t x .Since z is colored black at some time t z following t x , we know that the δ − 1 nodes ancestor of z are not black at time t x , since this is incompatible with the fact that z will become black.Since π is not corrupted, we know that y is black-free in T at time t x .This implies that y is colored black during the insertion of x in T , and hence y is black at time t ′ x contradicting our hypotheses.We proceed by analyzing subcase 2.2.At time t y all nodes in π[z : y], except for z, are white and hence the same is true at time t x .Since z is black at time t x and flag w ̸ = ⊤ for all nodes w in π[y : x), the AddLeaf procedure adding x will color y black.Hence y is black at time t ′ x .This is a contradiction.We now consider subcase 2.3.Together with Lemma 1, flag w = ⊤ implies the existence of a black node b in π(z : w].Since we assume all the nodes in π[y : x] to be white, the black node b is in π(z, y), contradicting the hypothesis of scenario 2.
◀ Now, we are ready to prove our main property about the pattern of black vertices discussed at the beginning of this section.See Figure 4 (d).
▶ Lemma 5. Let u and v be two nodes in T such that u is an ancestor of v, the distance between u and v is at least 7δ, and no node in the path π from u to v has been corrupted.Let ũ be the node at distance 5δ from u in π and let ṽ be the node at distance δ from v in π.Then there is a black node w * in π[ũ : v] such that: The distance between w * and ũ is at most δ.
A generic node in π[w * : ṽ] at distance d from w * is black iff d is a multiple of δ.Moreover, if w is a black vertex in π(w * , ṽ] and w is the associated black vertex in Q, the parent of w in Q corresponds to the δ-parent of w in π. Proof.Since no vertex in π has been corrupted, the path π must also belong to the noisy tree T .Then, Lemma 2 ensures that, at any time following the insertion of ũ in T , there exists a black ancestor y of ũ such that d π (y, ũ) ≤ 3δ.Such a vertex y is the δ-parent of some vertex x in π.We denote by u ′ the 2δ-parent of y in π and by t ′ x the time immediately after x is inserted.Since the length of π[u ′ : v] is at least 3δ and y be black when v is inserted, we can invoke Lemma 4 to conclude that there exists a node in π[y : x] that is black at time t ′ x .We choose w 0 as the closest ancestor of x that is black at time t ′ x .Moreover, for i = 1, . . ., ⌊|π[w 0 : v]|/δ⌋ we let w i be the unique vertex at distance δi from w 0 in π[w 0 , v].Finally, let t ′ i be the time immediately after the insertion of w i into T .We will prove by induction on i ≥ 1 that (i) at time t ′ i , all vertices w 0 , w 1 , . . ., w i−1 are black; (ii) from time t ′ i onward, all vertices in π[w 0 , w i ] that do not belong to {w 0 , w 1 , . . ., w i } are white.
We start by considering the base case i = 1.Regarding (i), we know that w 0 is black at time t ′ x , and hence w 0 is also black at time t ′ 1 (which cannot precede t ′ x ).Regarding (ii), by our choice of w 0 we know that at time t ′ x , the only black vertex in π[w 0 , x] is w 0 .Moreover, Algorithm 2 can only color a node b black if none of the δ − 1 lowest proper ancestors of b is black.This implies that no vertex in π(w 0 , w 1 ) will be colored black.
We now assume that the claim is true up to i ≥ 1 and prove it for i + 1.We first argue that the following property holds: (*) at time t ′ i+1 all vertices in π(w i : w i+1 ) are white.Indeed, suppose towards a contradiction that there exists some black vertex b in π(w i : w i+1 ) at time t ′ i+1 .When b was colored black, either its δ-parent b ′ was black or b was black-free.In the former case we immediately have a contradiction since b ′ must be a vertex of π(w i−1 , w i ) but all such vertices are white by the induction hypothesis.In the latter case b must have been colored black after the insertion of w i but, by the induction hypothesis, we know that from time t ′ i onwards w i−1 is black.This contradicts the hypothesis that b was black-free.Next, we prove (i).Suppose towards a contradiction that w i is white at time t ′ i+1 .Then, using (*) and the induction hypothesis, we can invoke Lemma 3 on the subpath of π between w i−1 and the parent of w i+1 to conclude that all nodes w in π[w i : w i+1 ) are such that flag w ̸ = ⊤.Hence, during the insertion of w i+1 , Algorithm 2 reaches line 8 and checks whether w i is near-a-black.Since this is indeed the case, a new black vertex is created in π[w i : w i+1 ), providing the sought contradiction.Let w i (resp.w i−1 ) be the vertex in Q associated with w i (resp.w i−1 ).Notice that this argument also shows that, at time t ′ i+1 , w i is a child of w i−1 in Q since w i becomes black after time t ′ i and not later than time t ′ i+1 , when w i−1 was already black.
To prove (ii) it suffices to notice that, by inductive hypothesis, we only need to argue about the nodes in π(w i : w i+1 ).From (*) we know that these nodes are white at time t ′ i+1 , while (i) ensures that w i is black at time t ′ i+1 .Then, a similar argument to the one used in the base case shows that Algorithm 2 will never color any node in π(w i : w i+1 ) black (as long as the nodes in π remain uncorrupted).This concludes the proof by induction.
Let w ′ be the node at distance δ from ũ in π[ũ : v].Notice that w 0 belongs to π[u : If w 0 lies in π(ũ : w ′ ], we can choose w * = w 0 .Otherwise, w 0 is an ancestor of ũ and, from (i) and (ii), there is exactly one black vertex b in π(ũ : w ′ ] and we choose w * = b.◀ The above lemma suggests a natural query algorithm.The query procedure is similar to the one for static case.When k ≤ 7δ we climb in T the nodes of the path from v to the k-parent of v in a trivial way.Otherwise, Lemma 5 ensures that if no vertex in the path P from v to its level ancestor in T was corrupted by the adversary, then every other δ-th vertex of P is colored black except, possibly, for an initial subpath of length δ and for a trailing subpath of length 5δ.The query procedure explicitly "climbs" these portions of P and queries D Q to quickly skip over its remaining "middle" part.The pseudo-code is given in Algorithm 3.
We are now ready to prove the main theorem of this section.
▶ Theorem 6.Our data structure requires linear space, supports the AddLeaf operation in O(δ) worst-case time, and can answer resilient LA queries in O(δ) worst-case time.
Proof.The correctness of the query immediately follows from Lemma 5.Moreover, the time required to perform an AddLeaf or an LA operation is O(δ) since in both cases O(δ) vertices of T are visited and a single O(δ)-time operation involving D Q is performed.
We now discuss the size of our data structure.Clearly, the space used to store the vector A of all records is O(n).We only need to argue about the size of D Q .Recall that D Q is the resilient version, obtained using the replication strategy, of the data structure that requires linear space, takes constant time to answer each LA query and to perform each AddLeaf operation [2].In order to show that D Q requires O(n) space we will argue that the number of black vertices is O( n δ ).As consequence we have that the size of To bound the number of vertices in Q, notice that in order to add a new vertex to Q we need to spend δ flags that were previously unspent.Moreover, a spent flag never becomes unspent unless the adversary corrupts the record of the corresponding node (by using one of its δ corruptions).As a consequence the nodes in Q are at most (n + δ)/δ = O(n/δ).◀
In this section we show how to handle weighted LA queries when δ and the weights of the nodes are polylogarithmically-bounded positive integers.Recall that, the answer to a weighted LA query LA(v, k) is the deepest ancestor u of v in T such that the total weight of the vertices in the path from u to v in T is at least k.The record of each node v stores, along to the fields described in Section 4, an additional field containing the weight of v. To store Q we use a data structure D Q that maintains a forest of rooted trees in which every vertex has an associated weight.D Q is also able to answer weighted LA queries on Q in O(δ) time.
For technical convenience we assume that a weighted level-ancestor query LA Q (v, k) in Q reports the vertex u of minimum depth among the ancestors of v such that the total weight of the vertices in the path between u and v (endpoints included) in Q is at most k.This data structure is the resilient version of the one in [2] which answers weighted LA queries in constant time when vertex weights are polylogarithmically-bounded.We modify Algorithm 2 in two ways: (i) during the discovery phase, we keep track of the total weight W of the vertices between x (included) and the closest black proper ancestor y ′ of y (y ′ excluded); (ii) during the execution phase, we keep track of the total weight W ′ of the vertices between x (included) and x ′ (excluded).Recall that when a vertex x ′ becomes black in the execution phase of in Algorithm 2 since y was observed to be near-a-black in the discovery phase, the corresponding vertex x ′ is added to Q via the AddLeaf Q operation on line 26.To handle weighted LA queries, we also need to assign a weight the the new vertex x ′ .Specifically, we choose this weight to be W − W ′ .Notice that, in the absence of corruptions, W − W ′ is exactly the total weight of the vertices in path between x ′ (included) and y ′ (excluded).Moreover, when a vertex y becomes black black in the execution phase of in Algorithm 2 because it was observed to be black-free in the discovery phase, we set the weight of the corresponding node y in Q to the weight of y in T . 6e now describe how to answer a query LA(v, k).We start by optimistically assuming that the (unweighted) distance between v and the sought vertex is short.We do so by climbing (up to) 10δ levels from v while keeping track of the total weight of the traversed vertices.We stop at and return the first encountered vertex for which such a weight is at least k.
If the above procedure is unable to locate the sought vertex, we proceed as follows.We climb δ levels from v, and we then search for a nearby black node b among the closest δ proper ancestors of the reached vertex.During this process, we keep track of the total weight W of the traversed nodes between v (included) and b (excluded).Let b be the vertex in Q that is associated with b.We now perform an LA Q (b, k − W ) query D Q to find the shallowest ancestor b ′ of b such that the overall weight W ′ of the vertices in the path between b ′ and b in Q is at most k − W .Let b ′ be the node of T that is associated to b ′ .Finally, we iteratively climb from b ′ towards its ancestors until we reach a vertex u such that the total weight of the path between b ′ (excluded) to u (included) is at least k − W − W ′ .We then return u.
As we argue below, this final climbing procedure requires at most 6δ steps in the absence of corruptions.Therefore, if this threshold is exceeded we immediately stop the query and report an error.
We now discuss the correctness of the query.Let u * be the deepest ancestor of v in T such that the total weight between v and u * is at least k, and assume that the path π between u * and v is uncorrupted.To prove that the query procedure is correct it is sufficient to show that (i) the vertex b ′ belongs π, and (ii) the (unweighted) length of π[u * : b ′ ] is at most 6δ.It remains to prove (ii).Since the number of vertices of π is at least 10δ, we invoke Lemma 5 to conclude that b ′ must be at distance at most 6δ from u * .Indeed, if this was not the case, then the δ-parent of b ′ would be black and would belong to π, which implies that b ′ could not be the vertex returned by the query on D Q .

BVQ queries.
The record of each node v stores the weight of v and maintains an additional field depth v that intuitively keeps track of the depth of v in T .Initially, when T is first built and consists only of the root r, we set depth r = 0. Whenever a new node v is appended as a child of u via the AddLeaf operation, we set depth v = depth u + 1.
To store Q we use a data structure D Q that that maintains a forest of rooted trees which can be updated by adding leaves in O(δ) time per operation.D Q is also able to answer (unweighted) LA and BVQ queries on Q in O(δ) time.This data structure is the resilient version of the one in [2] which answers both LA and BVQ queries in constant time.
Moreover, we slightly modify the execution phase of Algorithm 2 in the case in which y was observed to be near-a-black in the discover phase.In this scenario a vertex x ′ becomes black, and a corresponding vertex x ′ is added to Q via the AddLeaf Q operation on line 26.In our modification, we additionally climb the path from x ′ (included) to y ′ (excluded) while keeping track of the vertex w ′ of minimum weight among the encountered nodes.We assign the weight of w ′ to x ′ in Q and we store a reference to w ′ as (replicated) satellite data attached to x ′ .When instead the vertex that becomes black is y since y was observed to be black free during the discovery phase, we assign weight +∞ to the corresponding black node y in Q (no satellite data is needed in this case).
We now describe how to answer a BVQ(u, v) query.In particular, we only need to consider the case in which u is an ancestor of and v since we can always perform a LCA(u, v) query (we will show how to handle LCA queries later in this section) to find the lowest common ancestor z of u and v in T and then return the minimum of the two bottleneck queries BVQ(z, u) and BVQ(z, v) which satisfy the above requirement.
Hence we assume that no corrupted vertex exists in the path π from u to v in T and we start by computing the quantity d = depth u − depth v .Notice that, while depth u (and depth v ) might not contain the actual depth of u (and v) in T , due to a corruption in some ancestor of u, the value of d always matches the distance between u and v in T , i.e., the length of π. 7If d < 10δ, we answer the query using the trivial algorithm BVQ(u, v) that climbs the path π one edge at a time from v to u and return the vertex of minimum weight encountered in the process.Clearly this algorithm is resilient and requires O(δ) time.Otherwise, we use a strategy similar to the one used for LA queries in Algorithm 3. We climb δ levels from v, and we then search for a nearby black node b among the δ ancestors of the reached vertex.During this process, we keep track of the node w 1 of minimum weight among those we encounter.Next, we perform an LA query on D Q to find the black node b ′ that is (⌊d/δ⌋ − 7)-th parent of b (Lemma 5 ensures that this vertex exists and is black).Finally, we climb from b ′ to u in O(δ) time and keep track of a node w 2 having minimum weight among those encountered during the process.The answer to BVQ(u, v) is the vertex of minimum weight between w 1 , w 2 , and the node returned by a bottleneck vertex query BVQ(b ′ , b) in Q.

LCA queries.
The record of each node v stores, along with the fields described in Section 4, a field depth v managed as discussed for the BVQ query, and an additional field cba v which intuitively stores a pointer to the vertex in Q associated with the closest black ancestor of v in T .When v is inserted cba v is unset, and it will be possibly set during the execution phase of some later AddLeaf operation.Similarly to flag v , we allow a field cba v that is unset to be annotated with a pair (x, i), where x is a vertex that is being inserted and i is the observed distance between x and v.
To store Q we use a data structure D Q that maintains a forest of rooted trees which can be updated by adding leaves in O(δ) time per operation.D Q is also able to answer LA and LCA queries on Q in O(δ) time.This data structure can be obtained as combination of the resilient versions of the ones in [2,11] which answers LA and LCA queries in constant time.
We modify both the discovery and the execution phases of Algorithm 2. Recall that in the discovery phase the algorithm locates the δ-parent y of x, and the closest proper black ancestor y ′ of y, if any.In our modification, when we traverse a generic ancestor z of the inserted vertex x, we check cba z .If cba z is unset, we annotate it with (x, i) where i is the observed distance between x and z (possibly overwriting previous annotation).Moreover, we also store q y ′ in a variable y ′ in safe memory.In the execution phase, we only need to handle the case in which y appeared to be near-a-black during the discovery phase.In this case, let x ′ be the vertex such that y ′ is the δ-parent of x ′ (see line 23).In this case, we extend the for loop of line 18 in order to reach y ′ .We still check and spend the encountered flags only for the fist δ vertices as before.In addition, for each vertex z at distance i from x, such that z in the path between x ′ (included) and y ′ (excluded), we check that cba z is either set to y ′ or unset and (correctly) annotated with (x, i).In the latter case, we set cba z to y ′ .If neither of the previous conditions is met (i.e., cba z is set to some vertex other than y ′ or it is unset and incorrectly annotated) we are in an exceptional situation and cba z is left unaltered.
Finally, we modify line 26 in which x ′ is colored black via the addition of a corresponding vertex x ′ to Q.Our modification is as follows: If we are not in an exceptional situation, we proceed as before and we add x ′ as child of y ′ in Q.Otherwise, in the exceptional situation, we add x ′ as a new root in Q.
Before describing how to answer to a LCA query, we argue that the above modifications guarantee stronger structural properties than the ones given in Section 4. In particular, we show that Lemma 5 still holds.First of all, notice that our modifications do not affect vertex colors.Hence, we only need to show that the parent-child relationships between black vertices in Q are preserved.Since the only way to alter these relationships is for an exceptional situation to happen during the execution of AddLeaf that colors some node x ′ black, we only need to show that no exceptional situation can arise when a (sufficiently deep) vertex of an uncorrupted path becomes black.This is proven in the following.▶ Lemma 7. Let π be an ancestor-descendant path in T of length at least 2δ, and let x ′ be the deepest vertex of π.If x ′ is black and no vertex in π has been corrupted, then the execution of AddLeaf that colored x ′ black did not encounter an exceptional situation.
Proof.Let x be the node whose insertion in T cause x ′ to be colored black, and let t x the time immediately before x is inserted in T .In the rest of the proof, we assume that the execution of AddLeaf inserting x in T is in an exceptional situation, and we prove that this leads to a contradiction.
Since we are in an exceptional situation, at time t x the δ-parent y ′ of x ′ must be black and all the other nodes in π(y ′ : x ′ ) must be white.Let y ′ = q y ′ .Then, the exceptional situation was caused by a node w in π(y ′ : x ′ ] such that cba w = z and z ̸ = y ′ .Let z be the node in T that is associated with vertex z and notice that z ̸ = y ′ implies z ̸ = y ′ .Since no vertex in π is corrupted, the existence of w implies the existence of an ancestor z of w which is black at time t x and such that d(z, w) ≤ δ.By hypothesis, all the nodes in π(y ′ : x ′ ) are white at time t x , and hence z ̸ = y ′ must be a proper ancestor of y ′ .Node z satisfies the following conditions: (i) d(y ′ , z) ≤ δ − 1 (since d(w, z) ≤ δ), and (ii) y ′ was white when cba w was set to z (since cba w = z and no vertex in π is corrupted).This implies that, when y ′ was colored black, there was a black node z such that d(y ′ , z) ≤ δ − 1 and this is a contradiction.◀ We now prove a structural property that will be exploited in the query procedure.If we need to answer a LCA(u, v) query and both u and v are black, we can relate the lowest common ancestor of u and v in T with the lowest common ancestor of the corresponding vertices u and v (respectively) in Q.More precisely, let us assume that the path π between u and v in T is uncorrupted, and let w be the lowest common ancestor of u and v. Let a (resp.b) be the the shallowest ancestor of u (resp v) in Q such that the corresponding vertex a (resp.b) in T belongs to π[w : u] (resp.π[w : v]).
We prove the following lemma.
▶ Lemma 8.The distance between w and a (resp.b) in T is at most 6δ.Moreover, if both a and b have a parent in Q, then such parents coincide.
Proof.The bound on the distance between w and a (resp.b) in T immediately follows from Lemma 5, hence in the rest of the proof we focus on showing that that the parents of a and b (if they exist) must coincide.Assume, w.l.o.g., that a was inserted in Q before b, and let y ′ be the parent of a in Q.Notice that, when a was colored black, the corresponding AddLeaf operation inserted vertex a as a child of y ′ .Hence, the black vertex y ′ in T corresponding to y ′ was observed to be an ancestor of both a and w (by the choice of a) in the discovery phase.As a consequence, the execution phase ensured that the value of cba w is exactly y ′ (as otherwise the AddLeaf operation would have encountered an exceptional situation and a would have been a root of a tree in Q).Analogously, the AddLeaf operation that colored b black was not in an exceptional situation and, by the definition of b, we know that w lies in the (observed) path between b and its (observed) δ-parent z.Since w is uncorrupted, AddLeaf operation successfully checked that cba w matched q z , we conclude that q z = y ′ .Hence, the parent of b = y ′ .◀ We are now ready to describe how to answer to a LCA(u, v) query.We first describe a simple naive query that correctly handles the case in which at least one of u and v is close to their lowest common ancestor w.If this is not the case, this query will be inconclusive.
Let k be the difference between the depth of u and the depth of v. 8 We describe the case k ≥ 0 (the case k < 0 is symmetric).We perform an LA(v, k) query to find the k-parent v ′ of v. Notice that, in absence of corruptions, the distance between w and u is the same as the distance between w and v ′ .We now iteratively perform the following steps.We check whether v ′ = u, if this is the case we answer the query by reporting v ′ as the sought lowest common ancestor.Otherwise, we move u and v ′ to their respective parents and repeat.If the parent of u or v does not exist or we are unable to answer the query within 10δ iterations, we stop the above procedure and say that the naive query is inconclusive.
We now need to handle the case in which the naive query is inconclusive.For simplicity we first describe our strategy assuming that both u and v are black, and then we show how to handle a generic query.
Let u and v be the vertices in Q corresponding to u and v, respectively.We perform an LCA query in Q to find the lowest common ancestor y ′ of u and v, if any.We assume also that, if such a vertex exists, this query is able to return the two vertices a and b of Q such that y ′ is the parent of both u and v. 9 If the y ′ exists, we return the outcome of the naive LCA query on a and b, where a (resp.b) is the black vertex in T corresponding to a (resp.b).Lemma 8 ensures that the vertices a and b are close descendants of w, and hence the naive query correctly finds w.
It remains to handle the case in which y ′ does not exist, i.e., u and v belong to different trees of Q.In this case, we let a ′ (resp.b ′ ) be root of the tree in Q that contains u (resp.v).
From Lemma 8, it must be that a ′ = a or b ′ = b (possibly both).In this case, we inspect the fields depth u , depth v , depth a ′ and depth b ′ and we consider the vertex among a ′ and b ′ that appears to be deeper.W.l.o.g., let a ′ be such vertex and let k a ′ be the observed difference in levels between u and a ′ .We check that k a ′ is non-negative and that LA(u, k a ′ ) = a ′ .If the above condition is met, we perform a naive LCA query between a ′ and v.If this query answers with some vertex w ′ , it must be that w ′ = w and hence we return it.Otherwise, if k a ′ < 0, the answer LA(u, k a ′ ) was not a ′ , or the naive query was inconclusive, we must have b ′ = b and we return the result of the naive LCA query between b ′ and v.It remains to handle the case in which at least one among u and v is white.Since we already performed a naive query between u and v, we know that both distances between u and w, and v and w are more than 10δ.Hence, we climb from u (resp.v) until we reach the first black ancestor u ′ (resp.v ′ ) of u (resp.v).By Lemma 5, we must find such a node u ′ (resp.v ′ ) at distance at most 2δ from u (resp.v).We can now return the vertex reported by a LCA(u ′ , v ′ ) query, which can be answered as described above since both u ′ and v ′ are black.

Figure 1
Figure 1Illustration of resilient LA queries.The current tree T logically maintained by the data structure is depicted in (a).In this example, each vertex maintains a reference to its parent in T .In (b) some of the parent-child relationships have been altered by the adversary by corrupting the nodes highlighted in red.Since the algorithm cannot distinguish corrupted memory words from uncorrupted ones, its (defective) view of T is shown in (c).Nevertheless, a resilient data structure must still be able to correctly answer queries involving uncorrupted paths.For exampple, the query LA(v, k) is required to answer correctly for all (meaningful) values of k since the path from v to the root is uncorrupted, while query LA(w, k) is required to answer correctly for k ≤ 2. Since u is corrupted, the query LA(u, k) is allowed to answer incorrectly for every value of k.

Figure 3
Figure3 An example showing that an uncorrupted path π (depicted in blue) can exhibit an irregular pattern of black vertices (d).Situation (a) can be reached when the adversary corrupts r by setting flag r = ⊤ before the insertions of the other nodes take place.To obtain (b), the adversary can set flag u = flag v = ⊤, thus corrupting u and v before u and v's descendants are inserted.If the adversary sets flag u and flag v back to ⊥ before x, y, and z are inserted (in this order), we arrive in configuration (c) in which b1, b2, and b3 have been colored black.Inserting the remaining vertices yields (d).
To see (i), assume by contradiction that b ′ in not in π, and let b 1 the deepest ancestor of b in Q such that the vertex in T corresponding to the parent b 2 of b 1 in Q does not belong to π.Let b 2 the vertex in T associated to b 2 (vertex b 2 must exists since we assumed that b ′ is not in π).As a consequence, since π is uncorrupted, the total weight of the path in Q between b 1 (excluded) and b is equal to the total weight of π(b 1 , b].Moreover, the weight of b 1 in Q is at least the total weight of π[u * : b 1 ].This implies that W ′ must be strictly greater than k − W since b 2 has weight at least 1.This is a contradiction.
Add a new record x at the end of A; px ← xpar; flag x ← ⊥; qx ← null; // Discovery Phase 2 y ← x; // Check the flags of the lowest δ proper ancestors of x 3 for i = 1, . . ., δ do // Check whether y is near-a-black.// ℓ will be the distance to the closest proper black ancestor y ′ of y, if any 8 y ′ ← y; ℓ ← 0; near_black ← false; 9 while ℓ < δ and y ′ ̸ = r and near_black= false do 10 y ′ ← p y ′ ; ℓ ← ℓ + 1; ′ is black then near_black ← true; // If y is not near-a-black, check whether it is black-free 12 if near_black = false then 1 11 if y 13 z ← y ′ ; 14 for δ − 1 times do 15 if z = r then break; 16 z ← pz;