Proofs: LCP interval tree
These are the human proofs of LCP interval tree, at full length.
The stack scan builds the lcp-interval tree full
This proof shows: correctness, termination, time.worst.
Notation. , 0-based, no sentinel; a proper prefix sorts first. is the suffix of rank , for , and for the definitions . The end of a suffix counts as a symbol smaller than all others, so two different suffixes always differ at some depth. By the LCP-RMQ lemma, for . An -interval and its -indices are as on the page; for an interval , is its first -index. The root is with value 0.
Lemma 1 (intervals are branching substrings). For , is an -interval if and only if it is the set of ranks of the suffixes that start with some of length that is followed in by two different symbols (the end counts). In particular two lcp-intervals are nested or disjoint, and two different -intervals with the same are disjoint.
Proof. The suffixes that start with a given have consecutive ranks. () By condition 2 and the lemma, all with start with the same of length , and at an -index , and differ at depth . By conditions 1 and 3, and , if they exist, do not start with . () Let be the ranks of the suffixes that start with ; two of them differ at depth , so , all of are at least , and the minimum between those two is exactly . and because the neighbors do not start with . The last claim follows: for and , the sets are nested if one is a prefix of the other and disjoint otherwise.
Lemma 2 (children). Let have value and -indices (for the root, the 0-indices, possibly none). Each range is a single rank or an lcp-interval of value larger than , and every lcp-interval strictly inside lies inside one of them. So the lcp-intervals form a tree under containment, and these ranges are the children.
Proof. In a range with , the values exceed ; let be their minimum. is or an -index value , and is an -index value or , so both are below : is an -interval. An interval of value cannot have an -index in : then , and forces , and in the same way , so .
Invariant. At the start of the iteration with index (), the stack holds, from the bottom, the root and the lcp-intervals with , in order of increasing value, each with its correct ; and lists, in rank order, the child intervals of with . These intervals all contain rank , so by Lemma 1 they are nested, and their values are different, which gives the strict order.
For , no interval has , the stack is the root, and no lists are filled. Assume the invariant at , and let for and for . For an interval other than the root, acts as , since all their values are positive.
Step 1 (pops). An interval on the stack contains . If its value is greater than , it does not contain (else would be at least its value), so , which line L5 records. If its value is at most , it contains , since would need below its value. So L4 and L5 pop exactly the intervals that end at , and the others still satisfy .
Step 2 (push). The intervals with have value ; there is at most one, the -interval that contains , and only if . Line L7 pushes if and only if this exists. If , was not on the stack, and the top after the pops contains with a value at most ; it is not , so its value is less than . Conversely, if the top has a value less than and , the -interval that contains and is not on the stack (it would lie above the top and not be popped), so its first -index is .
Its left end is correct. Here . If , then . A popped interval ends at and starts before it, so ; hence nothing is popped, and from line L3. If , then , since ; with their minimum, is a -interval with , on the stack and popped. The last interval popped has the smallest value among the popped ones, so ; and , as both contain and has the larger value. So , and line L5 left .
Step 3 (children). Let be popped, and its parent in the tree of Lemma 2. Then is the child range of that ends at : either , or is a -index and . If is on the stack, it is the interval just below , since the stack is a chain under containment; and in both cases (in the first, ends at and is popped next, or is the root at with ). Line L6 appends to . If is not on the stack, then ; has an -index before every child that is not its first, so is its first child and , that is, . The interval below is then a proper ancestor of with a value less than , so line L6 keeps as , the loop stops, and line L8 makes the first child of . In all cases joins its parent's list after the children that closed earlier, so the lists are in rank order.
So the invariant holds at . At , every interval other than the root is popped and none is pushed, and line L9 sets . By Lemma 2 and the invariant, each lcp-interval was pushed once, at , closed with its correct ends, and attached to its parent. For the loop pushes nothing and the tree is the root.
Theorem (time). The build runs in time, and there are at most intervals besides the root.
Proof. Each iteration pushes at most one interval, at an index , so there are at most pushes, at most as many pops, and work besides. The loop has iterations, so it ends.