<p>The <em>least common ancestor</em> problem can be used to solve the reachability problem in dynamic rooted trees, so I imagine you will also be interested in the following: <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.52.783&amp;rep=rep1&amp;type=pdf" rel="nofollow">Optimal Algorithms for Finding Nearest Common Ancestors in Dynamic Trees</a>, by Alstrup and Thorup. This paper gives a time bound of $O(n + m \log \log n)$ for $n$ links and $m$ nca queries on a pointer machine.  </p>

CC BY-SA 3.0
2011-05-04T12:24:15.327Z
thank you for the reference.  The nearest common ancestor problem certainly solves reachability in trees.  The paper you linked to describes an incremental tree with all operations in $O(lg lg(n))$ time.  I wonder if it can be improved to work with fully dynamic trees as well.
bbejot
CC BY-SA 3.0
2011-05-04T07:11:36.963Z
2011-05-04T07:11:36.963Z
Shaun Harker
<p>Keep your integers in skip lists. Normal skip lists are ordered by key, but we will just use them as a representation of sequences. Additionally, maintain an array of pointers of size $n$. Each element of the array should point to a node in a skip list. I believe this supports $next$ in $O(1)$ and all other operations in $O(\lg n)$.</p>

<p>Specifically:</p>

<ul>
<li>$concat$ing or $split$ting two skip lists takes $O(\lg n)$ time and therefore invalidates at most $O(\lg n)$ pointers.</li>
<li>$next$ just follows the forward pointer at the leaf level, taking $O(1)$ time.</li>
<li>$first$ takes $O(\lg n)$ time: follow up pointers until you get stuck, then follow a left pointer. When you can't follow any more left pointers, you're at the head pointer of your skip list. Follow down pointers to the leaf, then one forward pointer. This is the first element in the list.</li>
<li>$follows$ is somewhat trickier. Proceed as in $first$ for $y$, but record a list of the values where you get stuck (that is, where you can't follow up pointers any more). We'll call this list you record a "trace". Do the same for $x$, but follow right pointers when you get stuck, not left. If $x$ precedes $y$, their traces will intersect. The traces are of size $O(\lg n)$. If each element in the trace is annotated with the stuck level, we can check for an intersection in time $O(\lg n)$.</li>
</ul>

<p>$next$ is worst-case $O(1)$, all others are $O(\lg n)$ <a href="http://www.google.com/search?q=%22with+high+probability%22">with high probability</a>. They can be made worst-case by using deterministic skip lists.</p>

<p>I think $concat$ can be made $O(\lg \lg n)$ by using leaf-level-linked (2,5) trees and boostrapping the spines. For the bootstrapping trick, see "<a href="http://www.math.tau.ac.il/~haimk/papers/loglog23.ps">Purely functional representations of catenable sorted lists</a>" by Kaplan and Tarjan.</p>

CC BY-SA 3.0
2011-05-03T03:58:46.917Z
cool. i was thinking about skip lists but couldn't quite see how to do follow without associated key values.
Sasho Nikolov
CC BY-SA 3.0
2011-05-03T13:21:21.197Z
This is great; I see how to make all the updates deterministic $O(lg(n))$, which is good.  I'll have to keep reading to understand the O(lg lg(n)).  Thanks for the post @jbapple.
bbejot
CC BY-SA 3.0
2011-05-03T02:56:28.887Z
2011-05-03T02:56:28.887Z
jbapple
<p>We have a set, $L$, of lists of elements from the set $N = \{ 1, 2, 3, ..., n \}$.  Each element from $N$ appears in a single list in $L$.  I am looking for a data structure which can perform the following updates:</p>

<ol>
<li><p>$concat(x, y)$ : concatenates the list containing $y$ onto the end of the list containing $x$</p></li>
<li><p>$split(x)$ : splits the list containing $x$ directly after $x$</p></li>
</ol>

<p>It also needs to perform the following queries:</p>

<ol>
<li><p>$follows(x, y)$ : returns $true$ if $x$ and $y$ are in the same list and $y$ comes after $x$ (but is not necessarily adjacent to $x$)</p></li>
<li><p>$first(x)$ : returns the first element of the list containing $x$</p></li>
<li><p>$next(x)$ : returns the the next element after $x$ in the list containing $x$</p></li>
</ol>

<p>I have already come up with a data structure which performs these updates in $O(lg^2 (n))$ and queries in $O(lg (n))$ time.  I'm mostly interested in whether or not there is already a data structure which can do this (hopefully faster?).</p>

<p>Motivation: rooted directed forests can be represented with two of these list sets and they allow quick calculation of reachability in such forests.  I want to see what else they can be used for and if all of this is already known.</p>

<ds.algorithms><graph-algorithms><ds.data-structures>
Does there exist a data structure for quick list manipulation and order queries?
bbejot
# Does there exist a data structure for quick list manipulation and order queries?

(Asked by: username_0 on 2011-05-02)

We have a set, $L$, of lists of elements from the set $N = \{ 1, 2, 3, ..., n \}$. Each element from $N$ appears in a single list in $L$. I am looking for a data structure which can perform the following updates:

1. $concat(x, y)$ : concatenates the list containing $y$ onto the end of the list containing $x$
2. $split(x)$ : splits the list containing $x$ directly after $x$

It also needs to perform the following queries:

1. $follows(x, y)$ : returns $true$ if $x$ and $y$ are in the same list and $y$ comes after $x$ (but is not necessarily adjacent to $x$)
2. $first(x)$ : returns the first element of the list containing $x$
3. $next(x)$ : returns the the next element after $x$ in the list containing $x$

I have already come up with a data structure which performs these updates in $O(lg^2 (n))$ and queries in $O(lg (n))$ time. I'm mostly interested in whether or not there is already a data structure which can do this (hopefully faster?).

Motivation: rooted directed forests can be represented with two of these list sets and they allow quick calculation of reachability in such forests. I want to see what else they can be used for and if all of this is already known.

**Tags:** ds.algorithms, graph-algorithms, ds.data-structures


---

## 2 answers

### Answer by username_2 on 2011-05-03. Score: 11 | Accepted answer

Keep your integers in skip lists. Normal skip lists are ordered by key, but we will just use them as a representation of sequences. Additionally, maintain an array of pointers of size $n$. Each element of the array should point to a node in a skip list. I believe this supports $next$ in $O(1)$ and all other operations in $O(\lg n)$.

Specifically:

* $concat$ing or $split$ting two skip lists takes $O(\lg n)$ time and therefore invalidates at most $O(\lg n)$ pointers.
* $next$ just follows the forward pointer at the leaf level, taking $O(1)$ time.
* $first$ takes $O(\lg n)$ time: follow up pointers until you get stuck, then follow a left pointer. When you can't follow any more left pointers, you're at the head pointer of your skip list. Follow down pointers to the leaf, then one forward pointer. This is the first element in the list.
* $follows$ is somewhat trickier. Proceed as in $first$ for $y$, but record a list of the values where you get stuck (that is, where you can't follow up pointers any more). We'll call this list you record a "trace". Do the same for $x$, but follow right pointers when you get stuck, not left. If $x$ precedes $y$, their traces will intersect. The traces are of size $O(\lg n)$. If each element in the trace is annotated with the stuck level, we can check for an intersection in time $O(\lg n)$.

$next$ is worst-case $O(1)$, all others are $O(\lg n)$ [with high probability](http://www.google.com/search?q=%22with+high+probability%22). They can be made worst-case by using deterministic skip lists.

I think $concat$ can be made $O(\lg \lg n)$ by using leaf-level-linked (2,5) trees and boostrapping the spines. For the bootstrapping trick, see "[Purely functional representations of catenable sorted lists](http://www.math.tau.ac.il/~haimk/papers/loglog23.ps)" by Kaplan and Tarjan.

> **Comments:**
> **username_3**: cool. i was thinking about skip lists but couldn't quite see how to do follow without associated key values.  
> **username_0**: This is great; I see how to make all the updates deterministic $O(lg(n))$, which is good.  I'll have to keep reading to understand the O(lg lg(n)).  Thanks for the post @username_2.  

---

### Answer by username_1 on 2011-05-04. Score: 1

The *least common ancestor* problem can be used to solve the reachability problem in dynamic rooted trees, so I imagine you will also be interested in the following: [Optimal Algorithms for Finding Nearest Common Ancestors in Dynamic Trees](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.52.783&rep=rep1&type=pdf), by Alstrup and Thorup. This paper gives a time bound of $O(n + m \log \log n)$ for $n$ links and $m$ nca queries on a pointer machine.

> **Comments:**
> **username_0**: thank you for the reference.  The nearest common ancestor problem certainly solves reachability in trees.  The paper you linked to describes an incremental tree with all operations in $O(lg lg(n))$ time.  I wonder if it can be improved to work with fully dynamic trees as well.  

---

