Abstract 1 Introduction 2 Background 3 Computing Minimal DAGs from Succinctly Encoded Trees 4 Supporting LCA Queries on our Compressed Minimal DAG 5 Experimental Results 6 Conclusion References Appendix A Missing Proofs Appendix B Missing Algorithms Appendix C Complete Experimental Results

Compressing Highly Repetitive Binary Trees with an Application to Range Minimum Queries

Gabriel Carmona111Alphabetical order, both authors contributed equally. ORCID Department of Computer Science, University of Pisa, Italy    Filippo Lari ORCID Department of Computer Science, University of Pisa, Italy
Abstract

Tree compression is a well-studied area that aims at reducing the size of tree representations by exploiting different forms of repetition. While the underlying theory is well understood, there is still significant room for experimental investigation, particularly in the design of compressed representations that efficiently support navigational queries.

In this work, we address the problem of designing, engineering, and experimentally evaluating a compression technique for unlabeled binary trees based on repeated subtrees, yielding the minimal Directed Acyclic Graph (DAG) of the input tree. We show how this representation can be computed in linear time and space directly from a succinct encoding of the tree, and how it can be augmented with compact auxiliary data structures to support Lowest Common Ancestor (LCA) queries.

When the input tree is the Cartesian tree of an array, LCA queries can be used to answer Range Minimum Queries (RMQs) on the underlying array. This is particularly relevant in the encoding model, where the array is not accessible at query time, and a space lower bound of 2nO(logn) bits is known. Given the numerous applications of RMQs, we use this problem as a case study for our experimental evaluation, testing our implementation on 11 real-world datasets. Our experiments show that, on almost every dataset, our implementation is the most space-efficient, using as few as 0.11n bits, while still delivering practical query times.

Keywords and phrases:
tree compression, range minimum query, compact data structures, algorithm engineering, experimental evaluation
Copyright and License:
[Uncaptioned image] © Gabriel Carmona and Filippo Lari; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation Design and analysis of algorithms
Supplementary Material:
Software  (Source Code): https://github.com/Yhatoh/CRMQ
  archived at Software Heritage Logo swh:1:dir:dda4044ad7d6a77395046f9c3019726de55717f8
Acknowledgements:
We would like to thank Paolo Ferragina and Giovanni Manzini for their valuable discussions on an early version of this article. Part of this work was carried out while Gabriel Carmona was visiting the Faculty of Computer Science at A Coruña University, and Filippo Lari was visiting the Department of Computer Science at TU Dortmund. We thank both institutions for their hospitality.
Funding:
This work has been developed within the project “Enhancing Compression and Search Capabilities in the Software Heritage Archive”, grant #G-2025-25193 (sloan.org), funded by the Alfred P. Sloan Foundation.
Editors:
Martin Aumüller and Irene Finocchi

1 Introduction

Tree compression techniques can be broadly classified into three main approaches: exploiting repeated subtrees, exploiting repeated tree patterns, and employing succinct data structures. Repeated subtrees are identical trees consisting of a node and all its proper descendants. Methods exploiting this form of repetition replace each repeated subtree by a pointer to its leftmost occurrence, resembling the Lempel-Ziv parsing of a string [32], and producing a Directed Acyclic Graph (DAG) representation DT. Among all DAGs representing a tree T, the minimal one is unique and can be computed in O(|T|) time [10], and its size can be exponentially smaller than that of the original tree 222A perfect binary tree of n nodes can produce a minimal DAG of size Θ(logn).. From an operational perspective, navigational queries on T can be supported in O(logn) time directly on DT by augmenting the minimal DAG with auxiliary data structures requiring O(|DT|) words of space [6].

Tree patterns generalize this notion by considering repeated connected subgraphs of T that do not necessarily correspond to whole subtrees. Techniques exploiting repeated tree patterns, most notably tree grammars, are capable of detecting a strictly larger class of repetitions and can be exponentially more compact than minimal DAGs [34]. This improvement in compression, however, comes at a cost: computing a minimal tree grammar is NP-Hard [8], and all known solutions require time proportional to the grammar height to answer navigational queries, which can be Ω(n). Recently, to mitigate this issue, a technique called top tree compression [5] has been introduced with the aim of exploiting tree patterns while simultaneously providing navigational queries in O(logn) time.

Succinct data structures represent trees in space close to their information-theoretic lower bound up to lower-order additive terms. It is well-known that general ordered unlabeled trees can be represented succinctly while still supporting a rich set of navigational queries in O(1) time [39]. Recently, hypersuccinct trees [36] have been introduced to provide an optimal representation for some (unlabeled) tree distributions. Still, there exist trees where DAG compression, tree grammars, and top-trees compress better than these representations.

However, while the theory of tree compression is well consolidated, to the best of our knowledge, except for succinct data structures, there are no available implementations based on repeated subtrees or tree patterns, focusing on providing navigational queries.

Tree representations are widely used to solve numerous data structure problems; among them, in this work we focus on the Range Minimum Query (RMQ) problem.

Given an array A[1..n] of n elements drawn from a totally ordered universe, an RMQ asks for the position of the leftmost minimum element in a range A[i,j]. In the encoding model, where the array A is not accessible after construction, any data structure must use at least 2nO(logn) bits of space in the worst case 333Any encoding can reconstruct the Cartesian tree of the input array, and their number grows asymptotically as 4n/n3/2π [18].. The first optimal solution achieving this bound up to lower-order terms while supporting O(1) time queries is due to Fischer and Heun [17]. Optimal solutions to the RMQ problem are based on the well-known reduction between RMQs on A and Lowest Common Ancestor (LCA) queries on the Cartesian tree of A, denoted hereafter as 𝒞(A). LCAs in turn reduce to a restricted version of RMQs, known as ±1RMQs, asking for the position of the minimum excess 444The difference between the number of ones and zeros in a given range of a bit vector. inside a given range of a bit vector B storing a succinct representation of 𝒞(A). Much work has been devoted to engineering solutions based on this sequence of reductions [22, 13, 2, 15].

Recently, several authors have proposed approaches to circumvent the aforementioned lower bound. One line of work exploits a restricted alphabet size in the design of the encoding [26], although this approach remains largely theoretical and rapidly approaches the general lower bound even for relatively small alphabets. Another direction seeks to reduce space by exploiting data compression techniques, including grammar compression and top-tree compression [19, 6], as well as hypersuccinct trees [36, 23]. Yet, these methods are mainly theoretical; the only one with an available implementation [23] exhibits query times that are an order of magnitude slower than state-of-the-art uncompressed solutions [22, 13, 2].

Given these premises, in this work, we consider the problem of engineering a tree compression technique with the aim of obtaining a truly practical compressed encoding for RMQs. In Section 3, we design a compressed representation of minimal DAGs of unlabeled binary trees, showing how such a representation can be efficiently computed in linear time and space starting from a succinct representation of the tree. In Section 4, we show how our compressed representation can be augmented in a non-trivial way to support, among many others, the LCA operation between two nodes, leading to the following result.

Theorem 1.

Let A be an array of n elements drawn from a totally ordered set, and let 𝒞(A) denote its Cartesian tree. Let nd be the number of nodes in the minimal DAG of 𝒞(A), p of which represent maximal identical subtrees, and L the length of its longest chain of copies. There exists an encoding data structure using 2nd+O(plogn)+o(nd) bits and answering RMQs on A in O(Llogn) time.

As we discuss in Section 4, our representation is theoretically more compact than existing ones [6, 5], at the cost of a possibly slower query time. In Section 5, through an extensive experimental evaluation on real-world datasets, we show that query times are often faster than those of state-of-the-art solutions [22, 13, 2]. Most importantly, our implementation achieves the smallest space usage on 9 out of 11 tested datasets, with the smallest being an impressive 0.11n bits, which is significantly less than the lower bound for RMQs.

2 Background

Given a string S of length n, a substring of S is any block S[i,j] with 1ijn. We refer to any substring of the form S[1,i] as a prefix of S, and to any S[i,n] as a suffix of S.

The Suffix Array (SA) [35] of S is an integer sequence SA[1..n] such that for any 2in, S[SA[i1],n]S[SA[i],n], where denotes the lexicographic ordering. The Longest Common Prefix (LCP) array [35] of a string S, denoted as LCP[2..n], is an array of integers such that for any 2in, LCP[i] is the length of the longest shared prefix between S[SA[i1],n] and S[SA[i],n]. Both can be computed in optimal O(n) time [27, 28, 30, 29].

Given a binary string (called bit vector) S[1..n] of length n, we consider the following fundamental operations for any symbol c{0,1}. rankc(S,i), which returns the number of occurrences of c in the prefix S[1,i), and selectc(S,i) that returns the position of the i-th occurrence of c in S from left to right 555We assume selectc(S,0)=0.. Both operations can be supported in O(1) time while using an optimal O(nloglogn/logn) bits of redundancy on top of S [24, 20].

A different space-time trade-off is possible when the bit vector is sparse, i.e., it contains mn ones. A very popular solution in this setting, although not optimal, is the so-called Elias-Fano encoding [12, 11], which uses 2m+mlog(n/m)+o(m) bits of space and answers rankc queries in O(min{log(n/m)+1,logm}) time and selectc queries in O(1) time.

In the following, we deal with ordered binary trees (called binary trees from now on). It is well known that a binary tree with n nodes can be represented as a sequence of 2n parentheses [37]. Among the various ways to realize such an encoding [24, 4, 9, 25], one that is particularly useful for our purposes is the following:

Definition 2 ([36]).

The balanced parenthesis encoding BP(t) of a binary tree t is recursively defined as follows:

BP(t)={ε,if t is empty;(BP(t))BP(tr),otherwise.

t and tr are the subtrees rooted at the left and right child of t, and ε is the empty string.

Given a binary tree t, its balanced parentheses sequence BP(t) can be represented as a bit vector Bt[1..2n] by encoding opening parentheses as 1s and closing parentheses as 0s. We drop the subscript whenever it is clear from the context.

Augmenting B with O(1) time support for rank and select, along with other o(n) bits data structures, many queries on the encoded tree can be performed in O(1) time [36]. For our purposes, we only mention two of them: find_close(B,i), which returns the index of the closing parenthesis matching the opening one at B[i]; enclose)(B,i), which returns the index of the first closing parentheses whose matching opening parenthesis encloses B[i].

3 Computing Minimal DAGs from Succinctly Encoded Trees

As already mentioned, our tree-compression technique targets unlabeled binary trees and exploits repeated subtree structures. Our goal is to design a compression method with the following two properties: first, it can be efficiently computed starting from a succinct representation of the given tree; second, it provides a compact representation of the resulting minimal DAG, while still providing efficient navigational queries.

To address the construction of the minimal DAG, we borrow a technique introduced by Carmona and Manzini [7], which was originally tailored to build minimal DAGs of k2-trees in the context of matrix compression, and adapt it to our setting in a non-trivial way.

Figure 1: An example of our compressed representation for minimal DAGs of binary trees. Arrows between nodes indicate maximal identical subtrees. The balanced parentheses sequence of the tree is obtained according to Definition 2. Nodes are conceptually labeled with their inorder numbers.

Let T be a binary tree of n nodes and B[1..2n] be its balanced parentheses representation computed as in Definition 2. We begin by showing how identical subtrees in T can be detected from the SA and LCP array of B. To this end, we introduce the following Lemmas whose proofs can be found in Appendix A.

Lemma 3.

Let B[1..2n] be a sequence of balanced parentheses. For every i such that B[i]=(, the size of the subtree starting at i is given by:

subtree_size(B,i)=(enclose)(find_close(B,i))i)/2
Lemma 4.

Let B[1..2n] be a sequence of balanced parentheses, and SA[1..2n] be its suffix array. For every i such that B[SA[i]]=(, let =subtree_size(B,SA[i]), if LCP[i]2 then the subtrees starting at positions SA[i] and SA[i1] in B are identical.

Using Lemma 3 and 4, all identical subtrees in T can be detected by simply scanning the suffix array SA of its balanced parentheses representation B. In particular, if there are k consecutive suffixes SA[i],,SA[i+k1] each corresponding to an identical subtree, then all these subtrees are identical. Therefore, for each such block of k identical subtrees, we select the leftmost one as the source, and all remaining ones are designated as copies. Compression is achieved by replacing copies with (smaller) pointers to their source subtree.

More precisely, we begin by scanning the SA from left to right. For each 1in, all starting positions of subtrees identical to the one beginning at B[SA[i]] (if any) will appear consecutively in the suffix array. Let SA[i+1],SA[i],,SA[i+k] be such a consecutive group of occurrences. While scanning these entries, we keep track of their minimum, i.e., the subtree starting at the leftmost position in B, which serves as the source. In a separate temporary array C[1..2n], initialized to all zeros, we mark each starting position of the copies in B with the position of their source.

After this initial phase, we construct the compressed balanced parentheses representation Bc of B as follows. We scan B from left to right, and for each 1i2n, if C[i]=0 we output the symbol B[i]; otherwise, position i marks the beginning of a copy whose source is C[i]. Let be the size of the source subtree. We output the parentheses sequence () corresponding to a leaf, to denote the presence of a copy, and then continue the scan from position i+. Since we proceed from left to right, this process skips any identical subtree contained within a larger one, and therefore only maximal identical subtrees are considered. As a result, the obtained sequence Bc corresponds to the balanced parentheses representation of the minimal DAG of T.

Let nd denote the number of nodes in the minimal DAG of T, and suppose that during the aforementioned process we identify a total of p (maximal) identical subtrees. To support decompression, we store the following additional information together with Bc (see Figure 1):

  • A bit vector R[1..2nd] that marks the closing parenthesis of a pointer in Bc

  • An integer array P[1..p] that stores, for each copy, the position of its source within B

By simultaneously scanning Bc and R, while properly accessing P, the original balanced parentheses sequence B can be reconstructed in Θ(n) time. Note that it is not necessary to store the size of each copied subtree. Since entire subtrees are replaced by pointers, during a copy operation we track the local excess of the pointed subtree starting from zero, and continue copying until reaching the first position where the excess returns to zero.

4 Supporting LCA Queries on our Compressed Minimal DAG

In this section, we consider the problem of supporting tree navigational queries on the minimal DAG representation of Section 3. In particular, we focus on the LCA operation, which in turn allows us to answer RMQs (recall Section 1), and will serve as a case study in our experimental evaluation of Section 5. To this end, we first observe that any navigational query requires a mapping between positions of the uncompressed and compressed representation, i.e., between B[1..2n] and Bc[1..2nd].

4.1 Mapping Between Positions of 𝑩 and 𝑩𝒄

To construct such mapping functions, we begin by augmenting the representation of Section 3 with a bit vector S[1..2n], which marks with 1s the positions corresponding to the beginning (the first opening parenthesis) and the end (the last closing parenthesis) of each copied subtree in B; see the example in Figure 1. Moreover, we augment the bit vector R from Section 3 with support for rank1 and select1 operations. Converting a position in B to a position in Bc, and vice versa, can then be performed using the following auxiliary functions:

  • ϕ(i): Given a position i in B, return a position in Bc. If i is contained inside a copied subtree, return the position of the closing parenthesis of the corresponding pointer in Bc; Otherwise, return the properly scaled position of the same parenthesis in Bc. Let r=rank1(S,i). Then:

    ϕ(i)={select1(R,(r+1)/2),if r is odd,select1(R,r/2)+(iselect1(S,r)),otherwise. (1)
  • ϕ1(j): Given a position j in Bc, return a position in B. If i corresponds to a pointer, return the starting position of the copied subtree in B; Otherwise, return the properly scaled position of the same parenthesis in B. Let r=rank1(R,j). Then:

    ϕ1(j)={select1(S,2r+1),if R[j]=1,select1(S,2r)+(jselect1(R,r)),otherwise. (2)

We give the intuition behind our formulation using the example in Figure 1. Consider the computation of ϕ for i=20. First, we compute r=rank1(S,i), which is equal to 2, indicating that position i lies outside a copied subtree in B. Next, we compute the position in Bc corresponding to the copy immediately preceding i, namely select1(R,r/2)=12. Finally, to obtain the result, we compute the distance between i and the end of the copy immediately preceding it as (iselect1(S,r))=4. Adding this distance to the previous quantity yields ϕ(20)=12+4=16. A similar idea is used to compute ϕ1.

The efficiency of ϕ and ϕ1 depends on the implementation of S and R. In theory, both can be supported in O(1) time, e.g., by resorting to [41, 40]. However, since we strive for a practical implementation, we refrain from doing so and instead adopt the Elias-Fano encoding described in Section 2. As a consequence, since S and R contain p ones (i.e., the number of copies found by the procedure of Section 3) and have lengths n and ndn, respectively, implementing both mappings requires O(plog(n/p)) bits of space and O(logn) time.

4.2 Supporting LCA Queries

In the balanced parentheses representation of Definition 2, each node of the underlying tree is identified by the position of its closing parenthesis. An LCA query, therefore, takes as input two such positions u and v and returns the position of the closing parenthesis corresponding to their lowest common ancestor. As discussed in Section 1, this operation can be reduced to a ±1RMQ on the balanced parentheses sequence, which asks for the position of the minimum excess in the range B[u,v]. For example, in Figure 1, the LCA of u=24 and v=27 is given by ±1RMQB(24,27)=25, since the minimum excess in that range occurs at position 25.

This restricted version of RMQs can be solved in O(1) time using o(n) bits of space by resorting to standard precomputed tables [3, 42, 17]. However, this requires accessing the balanced parentheses representation B, which is not available in our setting.

In this section, we show how to overcome this issue, answering an LCA query between two nodes u and v directly on our compressed format. To this end, we begin by distinguishing the following three cases. Examples are shown in parentheses and refer to Figure 1. Recall that nodes are represented by the position of their closing parenthesis in B.

  1. 1.

    Neither u nor v belongs to a copied subtree (u=5 and v=20).

  2. 2.

    Exactly one of u and v belongs to a copied subtree (u=6 and v=14).

  3. 3.

    Both u and v belong to different copied subtrees (u=14 and v=28).

Intuitively, since in all of the above cases the ancestor-descendant relationships in B are preserved in Bc, the LCA of u and v can be obtained by computing the LCA of ϕ(u) and ϕ(v) in Bc, i.e. ±1RMQBc(ϕ(u),ϕ(v)), and mapping the result back to B using ϕ1.

This property no longer holds when u and v belong to the same copied subtree. Consider nodes u=24 and v=30 in Figure 1. In this case, the key idea is to recursively follow the pointer to the common source of both nodes until one of the three base cases is reached.

To formalize this idea, we describe a single step of this recursive approach. Please refer to Figure 1 for a running example. We first compute the starting position m of the copied subtree containing both u and v in B, that is, m=select1(S,rank1(S,u)) (note that u and v are interchangeable here). Next, we determine the starting position s of the corresponding source subtree in B by accessing the pointer array P. We then map u and v to positions within the source by setting u=s+(um) and v=s+(vm). The LCA query is then solved recursively for u and v, and the recursion ends after reaching one of the base cases.

Notice that each recursive calls return the position of the LCA within the source subtree. To translate this position back to the copied subtree, we compute its offset with respect to the start of the source s and add this offset to m. The complete procedure for computing the LCA of two nodes in our compressed representation is presented in Algorithm 1.

Considering the cost of our algorithm, the ±1RMQs on Bc can be solved in O(1) time using one of the approaches in [3, 42, 17] (we comment in Section 5 about their practicality). Overall, this only adds o(nd) bits of space to our representation.

Moreover, each recursive call requires O(logn) time, due to the rank1 and select1 operations on S, as well as the calls to ϕ and ϕ1 (see Section 4.1). The total number of recursive calls is proportional to the length of the longest chain of copies L in the minimal DAG representation of the underlying tree. Considering the example in Figure 1, we have L=2. Consequently, the overall running time of Algorithm 1 is O(Llogn).

Algorithm 1 The recursive LCA computation on our compressed representation.

4.3 Supporting RMQs

Given an array A, supporting LCA queries on its Cartesian tree 𝒞(A) allows us to answer RMQs on A. Since LCA queries are in turn reduced to ±1RMQs on the balanced parentheses sequence B of 𝒞(A), it is necessary to map indices of A into positions of B, and vice versa.

By Definition 2, the value at position i in A corresponds to the node visited at step i during an inorder traversal of 𝒞(A) (i.e., the node with inorder number i). The closing parenthesis of this node is therefore located at position select0(B,i) in B. Conversely, a closing parenthesis at position i in B corresponds to the value at position rank0(B,i) in A. As a consequence, RMQs can be formulated as follows [36]:

RMQA(i,j)=rank0(±1RMQB(select0(i),select0(j))) (3)

Notice that the inner part of Equation 3 corresponds to the LCA between the nodes select0(i) and select0(j), and is computed as described in Section 4. What remains is to show how to answer rank0 and select0 queries on B using our compressed representation.

To this end, for each copy we store the rank0 value (i.e., the inorder number) of its rightmost child in a separate array using O(plogn) bits overall. For example, in Figure 1 we store the values 7 and 15 for the first and second copy, respectively. Using this array, we can support both rank0 and select0 queries on B by following a recursive strategy similar to the one used for LCA queries in Section 4. We defer a complete description to Appendix B; here we only mention that both operations can be done in O(Llogn) time, where L is again the longest chain of copies in the minimal DAG of 𝒞(A).

4.4 Wrapping up the Final Result

We conclude by summarizing our main result. Given an array A[1..n], let nd be the number of nodes in the minimal DAG of its Cartesian tree 𝒞(A), of which p=o(nd) are copies. The overall space usage of our data structure is 2nd+O(plogn)+o(nd) bits, and within such space it supports RMQs in O(Llogn) time. This proves Theorem 1.

Our representation is theoretically more compact than existing ones [6, 5] that use O(nd) words of space (i.e., O(ndlogn) bits) at the cost of a possibly slower query time. Indeed, L can be as large as O(n) in the worst case (see Appendix A). However, our experimental results show that L never exceeds logn, and is significantly smaller on average (see Table 1).

In the next section, we present an extensive experimental evaluation on real-world datasets, showing that query times in practice are often faster than those of state-of-the-art implementations [22, 13, 2], while achieving the smallest space usage on 9 out of 11 datasets.

5 Experimental Results

We run our experiments on an Ubuntu machine equipped with 394 GiB of RAM and an Intel Xeon Gold 6132 processor running at 2.60 GHz. Our implementation is written in C++ and has been tested for correctness using the googletest framework 666https://github.com/google/googletest. Both our implementation and the benchmarking suite are available at https://github.com/Yhatoh/CRMQ.

5.1 Implementation Notes

To obtain a practical implementation of RMQs, we introduce the following optimizations. We use a sparse table [3], that is, a table storing all answers to RMQs for dyadic intervals 777Intervals whose length is a power of 2., built over samples of the input array. After an initial experimental evaluation, we set the sampling frequency to 212 to achieve the best space-time trade-off.

The rationale behind this engineering trick is that for large ranges, the position returned by the sparse table is often correct and can be reported directly as the answer. This intuition is confirmed by the results in Figure 2, which show the percentage of queries solved directly using the sparse table for different query sizes. In particular, approximately 70%, 80%, and nearly 100% of queries of length 104, 105, and 106, respectively, are solved immediately using this technique. As we show in Section 5.3, this optimization adds only a moderate space overhead while significantly accelerating such queries.

Since most long queries are answered using the aforementioned sparse table, we are left only with short queries of length 101103. These queries are very likely to map to short ranges in the balanced parentheses sequence of the Cartesian tree. Moreover, we expect the compressed balanced parentheses to be much shorter than the uncompressed ones. Therefore, to solve the ±1RMQ queries in Algorithm 1, we avoid complex solutions designed to handle arbitrary ranges and to scale to large instances [3, 42, 17, 13, 15], and instead use linear scans accelerated by precomputed tables storing the answers for blocks of 16 bits each. These tables fit within the cache of most architectures and introduce only a negligible space overhead.

Considering the longest chain of copies L, which controls the time complexity of our queries (see Theorem 1), Table 1 shows that this parameter never exceeds logn on any of the tested datasets. Moreover, the average chain length is much smaller than the maximum.

Lastly, some components of our compressed representation rely on existing libraries. The SA and LCP arrays of Section 3 are implemented using the highly optimized libsais library [21]. For the Elias-Fano representation of the sparse bit vectors in Sections 3 and 4, we use the broadword implementation provided by the SUX library [44]. For the plain bit vector of the compressed balanced parentheses, which requires support for rank and select operations, we use the most efficient implementation to date from the pasta library [31].

5.2 Datasets, Queries, and Competitors

To assess the performance of our implementation, we consider real-world datasets. In particular, we use the LCP array of texts coming from the repetitive and non-repetitive collections of the Pizza & Chili corpus [16]. Among many others, this can be seen as a practical application, since RMQs on the LCP array of a text, in combination with its suffix array, can be used to speed up pattern matching queries [14]. In all the following experiments, to measure the space-time performance, we generate 102 random queries for each range of size {101,102,,105,106}. We measure the average query time in nanoseconds and the space usage in bits per element (bpe), comparing the following implementations:

  • CRMQ<t>: Our implementation of the data structure of Theorem 1, where only maximal identical subtrees of size at least t are compressed.

  • Succinct: A practical version of the optimal solution by Fischer and Heun, due to Grossi and Ottaviano [22], implemented in the succinct library.

  • RMM: The implementation of Ferrada and Navarro [13], which uses a range min–max tree to solve ±1RMQs on the balanced parentheses.

  • RecRMQ<s,Λ,d>: The recursive approach by Baumstark et al. [2], which partitions the excess array of the Cartesian tree into blocks of size s across Λ levels of recursion. At each level, it stores the minimum excess value of each block. After Λ levels, the recursion terminates, and a sparse table is used to answer queries. Additionally, a top-level sparse table built over blocks of size d can be used to further accelerate queries as we do.

  • HyperRMQ<b>: A practical implementation of the hypersuccinct trees by Munro et al. [36], due to Hamada et al. [23]. Each micro-tree contains fewer than 2b nodes and is encoded using an entropy coder that the authors named depth-first arithmetic coding.

5.3 Evaluation

For the sake of presentation, only the most representative subset of the experimental results is shown in Figure 3; the complete results are reported in Appendix C.

Table 1: Statistics from our experimental evaluation on the Pizza & Chili corpus. The table reports the LCP array size, the maximum and average chain length L, and the number and average size of copied subtrees in the minimal DAG of the Cartesian tree of the LCP array. All minimal DAG statistics are computed without forcing a threshold on the minimum subtree size. Averages are reported together with their standard deviation.
Dataset LCP size (n×108) logn max. chain length L avg. chain length copies (×106) avg. subtree size (×102)
Repetitive
CERE 4.61 28.78 18 4.41±1.66 12.08 0.74±0.93
COREUTILS 2.05 27.61 23 4.81±1.87 4.52 0.88±17.75
EINSTEIN 4.68 28.80 18 7.41±1.97 0.23 39.86±144.93
ESCHERICHIA 1.13 26.75 11 3.33±1.42 7.39 0.26±0.15
INFLUENZA 1.55 27.21 17 4.64±1.90 2.58 11.17±46.36
KERNEL 2.58 27.94 16 5.04±1.73 3.33 15.27±125.61
PARA 4.29 28.67 17 4.30±1.74 15.02 0.54±0.62
Non-repetitive
DBLP 2.96 28.14 15 4.32±1.97 7.28 0.75±72.16
DNA 4.03 28.59 16 2.79±1.26 33.74 0.20±0.10
ENGLISH 22.10 27.72 17 3.14±1.69 142.95 0.24±11.57
PROTEINS 11.84 30.14 18 3.41±1.90 74.33 0.25±0.64
SOURCES 2.11 27.65 17 3.43±1.84 8.74 0.31±34.99
Figure 2: Effectiveness of the top-level sparse table described in Section 5.1 on the datasets of Section 5.3. For each range size on the x-axis, the percentage of queries that are immediately solved with the sparse table is reported on the y-axis. See Appendix C for the complete results.
Figure 3: The most representative sample of our experimental results, showing space usage in bits per element on the y-axis and query time in nanoseconds on the x-axis. Points closer to the origin correspond to solutions with better space-time trade-offs. The light gray region below a space usage of 2 bits per element corresponds to the lower bound of encoding data structures for RMQs; it therefore separates succinct solutions from compressed ones (such as ours), which are in principle able to go below this lower bound. Missing solutions in some plots indicate that we were not able to run them on those specific instances.

We begin by observing that both Succinct (olive squares) and RMM (orange bullets) consistently yield the worst space-time trade-offs across all tested datasets. Consequently, we exclude them from our comparison, focusing on solutions that offer a better trade-off.

We next consider the only available implementation based on a compressed encoding, namely HyperRMQ (blue right-oriented triangles). Although it goes slightly below the lower bound of 2 bpe on a few datasets (3 out of 11, see Appendix C), it is always the slowest among all competitors, with query times on the order of 103 nanoseconds. We therefore proceed by comparing RecRMQ with our implementation.

Starting with RecRMQ (purple stars), we observe that it offers the best space-time trade-offs among the previously discussed solutions (i.e., Succinct, RMM, and HyperRMQ) across all datasets and query ranges. In particular, query times are often in the range of hundreds of nanoseconds for small ranges 101104, and drop to tens of nanoseconds for larger ones, that is, 105106. This highlights the benefit of using the top-level sparse table, as discussed in Section 5.1. In terms of space usage, as expected, RecRMQ always uses more than 2 bpe.

Finally, turning to our CRMQ (red crosses), we first note that for small query ranges, that is, 101103, our solution is not particularly efficient and is only slightly better than HyperRMQ. We believe this is because, for such queries, the probability that the two nodes of the Cartesian tree lie in the same copy is high. This triggers recursive calls in Algorithm 1, which, although few in number (see Table 1), introduce a non-negligible overhead. This behavior changes significantly when considering larger query ranges, namely 104106. In this regime, queries are more likely to be solved by the top-level sparse table, or after only a few recursive calls. As a result, on most datasets, our solution is on par with RecRMQ.

Moving to the space usage, our CRMQ is almost always the most space-efficient, going below the lower bound of 2 bpe on 9 out of 11 datasets (see Appendix C). In particular, on the repetitive portion of the Pizza & Chili dataset (first two rows of Figure 3), the smallest space usage is an impressive 0.11 bpe, corresponding to a reduction of 95% with respect to the second most space-efficient solution. On non-repetitive texts (last two rows of Figure 3), the improvement is less pronounced but still substantial: the minimum space usage is around 0.81 bpe, i.e., 61% smaller than the second best solution.

Overall, the experimental evaluation shows that, when space efficiency is a primary concern or when queries are of medium to large size, our approach should be the solution of choice, as it achieves a significant space reduction while still delivering fast query times.

6 Conclusion

We design, engineer, and experimentally evaluate a novel representation of minimal DAGs for unlabeled binary trees that is theoretically more compact than existing ones and can be efficiently computed starting from a succinct encoding of the input tree.

We then consider the problem of supporting LCA queries on this representation. We focus on this operation in particular because, when the input tree is the Cartesian tree of an array, LCA queries can be used to answer RMQs on the underlying array.

Given the numerous applications of RMQs in string processing, text indexing, and data compression, we use them as a case study for an experimental evaluation on several real-world datasets. Our results show that across almost every dataset, our implementation is the most space-efficient, using as few as 0.11n bits of space while delivering practical query times ranging from tens to thousands of nanoseconds, depending on the range size.

Future research directions include: further reducing space by entropy coding the pointer vector P, in the same spirit as [36]; given the performance obtained on LCPs of repetitive texts, an interesting problem would be to link our space usage to known repetitive measures of the underlying texts [38]; engineer our implementation with vectorized instructions [43]; devise an algorithm to cut chains of copies above a given length at construction time, trading space for time as in [33, 1], thus possibly improving the theoretical query time.

References

  • [1] Hideo Bannai, Mitsuru Funakoshi, Diptarama Hendrian, Myuji Matsuda, and Simon J. Puglisi. Height-bounded lempel-ziv encodings. In 32nd Annual European Symposium on Algorithms, ESA 2024, Royal Holloway, London, United Kingdom, September 2-4, 2024, volume 308 of LIPIcs, pages 18:1–18:18. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2024. doi:10.4230/LIPIcs.ESA.2024.18.
  • [2] Niklas Baumstark, Simon Gog, Tobias Heuer, and Julian Labeit. Practical range minimum queries revisited. In 16th International Symposium on Experimental Algorithms, SEA 2017, June 21-23, 2017, London, UK, volume 75 of LIPIcs, pages 12:1–12:16. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2017. doi:10.4230/LIPIcs.SEA.2017.12.
  • [3] Michael A. Bender and Martin Farach-Colton. The LCA problem revisited. In LATIN 2000: Theoretical Informatics, 4th Latin American Symposium, Punta del Este, Uruguay, April 10-14, 2000, Proceedings, volume 1776 of Lecture Notes in Computer Science, pages 88–94. Springer, 2000. doi:10.1007/10719839_9.
  • [4] David Benoit, Erik D. Demaine, J. Ian Munro, Rajeev Raman, Venkatesh Raman, and S. Srinivasa Rao. Representing trees of higher degree. Algorithmica, 43(4):275–292, 2005. doi:10.1007/S00453-004-1146-6.
  • [5] Philip Bille, Inge Li Gørtz, Gad M. Landau, and Oren Weimann. Tree compression with top trees. Inf. Comput., 243:166–177, 2015. doi:10.1016/J.IC.2014.12.012.
  • [6] Philip Bille, Gad M. Landau, Rajeev Raman, Kunihiko Sadakane, Srinivasa Rao Satti, and Oren Weimann. Random access to grammar-compressed strings and trees. SIAM J. Comput., 44(3):513–539, 2015. doi:10.1137/130936889.
  • [7] Gabriel Carmona and Giovanni Manzini. Depth first representations of k2-trees. In Golnaz Badkobeh, Jakub Radoszewski, Nicola Tonellotto, and Ricardo Baeza-Yates, editors, String Processing and Information Retrieval, pages 28–44, Cham, 2026. Springer Nature Switzerland.
  • [8] Moses Charikar, Eric Lehman, Ding Liu, Rina Panigrahy, Manoj Prabhakaran, Amit Sahai, and Abhi Shelat. The smallest grammar problem. IEEE Trans. Inf. Theory, 51(7):2554–2576, 2005. doi:10.1109/TIT.2005.850116.
  • [9] O’Neil Delpratt, Naila Rahman, and Rajeev Raman. Engineering the LOUDS succinct tree representation. In Experimental Algorithms, 5th International Workshop, WEA 2006, Cala Galdana, Menorca, Spain, May 24-27, 2006, Proceedings, volume 4007 of Lecture Notes in Computer Science, pages 134–145. Springer, 2006. doi:10.1007/11764298_12.
  • [10] Peter J. Downey, Ravi Sethi, and Robert Endre Tarjan. Variations on the common subexpression problem. J. ACM, 27(4):758–771, 1980. doi:10.1145/322217.322228.
  • [11] Peter Elias. Efficient storage and retrieval by content and address of static files. J. ACM, 21(2):246–260, 1974. doi:10.1145/321812.321820.
  • [12] Robert M. Fano. On the number of bits required to implement an associative memory. Technical report, Massachusetts Institute of Technology, Project MAC, Computer Structures Group, 1971.
  • [13] Héctor Ferrada and Gonzalo Navarro. Improved range minimum queries. J. Discrete Algorithms, 43:72–80, 2017. doi:10.1016/J.JDA.2016.09.002.
  • [14] Paolo Ferragina. Pearls of Algorithm Engineering. Cambridge University Press, 2023.
  • [15] Paolo Ferragina and Filippo Lari. FL-RMQ: A learned approach to range minimum queries. In 36th Annual Symposium on Combinatorial Pattern Matching, CPM 2025, Milan, Italy, June 17-19, 2025, volume 331 of LIPIcs, pages 7:1–7:23. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2025. doi:10.4230/LIPIcs.CPM.2025.7.
  • [16] Paolo Ferragina and Gonzalo Navarro. Pizza and chili. https://pizzachili.dcc.uchile.cl/, 2005. Accessed: 2025-12-08.
  • [17] Johannes Fischer and Volker Heun. Space-efficient preprocessing schemes for range minimum queries on static arrays. SIAM Journal on Computing, 40(2):465–492, 2011. doi:10.1137/090779759.
  • [18] Philippe Flajolet and Robert Sedgewick. Analytic Combinatorics. Cambridge University Press, 2009.
  • [19] Pawel Gawrychowski, Seungbum Jo, Shay Mozes, and Oren Weimann. Compressed range minimum queries. Theor. Comput. Sci., 812:39–48, 2020. doi:10.1016/J.TCS.2019.07.002.
  • [20] Alexander Golynski. Optimal lower bounds for rank and select indexes. Theor. Comput. Sci., 387(3):348–359, 2007. doi:10.1016/J.TCS.2007.07.041.
  • [21] Ilya Grebnov. libsais. https://github.com/IlyaGrebnov/libsais, 2026. Accessed: 2026-01-19.
  • [22] Roberto Grossi and Giuseppe Ottaviano. Design of practical succinct data structures for large data collections. In Experimental Algorithms, 12th International Symposium, SEA 2013, Rome, Italy, June 5-7, 2013. Proceedings, volume 7933 of Lecture Notes in Computer Science, pages 5–17. Springer, 2013. doi:10.1007/978-3-642-38527-8_3.
  • [23] Kou Hamada, Sankardeep Chakraborty, Seungbum Jo, Takuto Koriyama, Kunihiko Sadakane, and Srinivasa Rao Satti. A simple representation of tree covering utilizing balanced parentheses and efficient implementation of average-case optimal rmqs. In 32nd Annual European Symposium on Algorithms, ESA 2024, September 2-4, 2024, Royal Holloway, London, United Kingdom, volume 308 of LIPIcs, pages 64:1–64:18. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2024. doi:10.4230/LIPIcs.ESA.2024.64.
  • [24] Guy Jacobson. Space-efficient static trees and graphs. In 30th Annual Symposium on Foundations of Computer Science, Research Triangle Park, North Carolina, USA, 30 October - 1 November 1989, pages 549–554. IEEE Computer Society, 1989. doi:10.1109/SFCS.1989.63533.
  • [25] Jesper Jansson, Kunihiko Sadakane, and Wing-Kin Sung. Ultra-succinct representation of ordered trees with applications. J. Comput. Syst. Sci., 78(2):619–631, 2012. doi:10.1016/J.JCSS.2011.09.002.
  • [26] Seungbum Jo and Srinivasa Rao Satti. Encodings for range minimum queries over bounded alphabets. Theor. Comput. Sci., 1070:115824, 2026. doi:10.1016/J.TCS.2026.115824.
  • [27] J. Kärkkäinen, P. Sanders, and S. Burkhardt. Linear work suffix array construction. Journal of the ACM, 53(6):918–936, 2006. doi:10.1145/1217856.1217858.
  • [28] Juha Kärkkäinen, Giovanni Manzini, and Simon J Puglisi. Permuted longest-common-prefix array. In Combinatorial Pattern Matching: 20th Annual Symposium, CPM 2009 Lille, France, June 22-24, 2009 Proceedings 20, pages 181–192. Springer, 2009. doi:10.1007/978-3-642-02441-2_17.
  • [29] D. K. Kim, J. S. Sim, H. Park, and K. Park. Linear-time construction of suffix arrays. In Proc. 14th Symposium on Combinatorial Pattern Matching (CPM ’03), pages 186–199. Springer-Verlag LNCS n. 2676, 2003.
  • [30] P. Ko and S. Aluru. Space efficient linear time construction of suffix arrays. In Proc. 14th Symposium on Combinatorial Pattern Matching (CPM ’03), pages 200–210. Springer-Verlag LNCS n. 2676, 2003.
  • [31] Florian Kurpicz. Engineering compact data structures for rank and select queries on bit vectors. In String Processing and Information Retrieval - 29th International Symposium, SPIRE 2022, Concepción, Chile, November 8-10, 2022, Proceedings, volume 13617 of Lecture Notes in Computer Science, pages 257–272. Springer, 2022. doi:10.1007/978-3-031-20643-6_19.
  • [32] Abraham Lempel and Jacob Ziv. On the complexity of finite sequences. IEEE Trans. Inf. Theory, 22(1):75–81, 1976. doi:10.1109/TIT.1976.1055501.
  • [33] Zsuzsanna Lipták, Francesco Masillo, and Gonzalo Navarro. BAT-LZ out of hell. In 35th Annual Symposium on Combinatorial Pattern Matching, CPM 2024, June 25-27, 2024, Fukuoka, Japan, volume 296 of LIPIcs, pages 21:1–21:17. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2024. doi:10.4230/LIPIcs.CPM.2024.21.
  • [34] Markus Lohrey and Sebastian Maneth. The complexity of tree automata and xpath on grammar-compressed trees. Theor. Comput. Sci., 363(2):196–210, 2006. doi:10.1016/J.TCS.2006.07.024.
  • [35] U. Manber and G. Myers. Suffix arrays: a new method for on-line string searches. SIAM Journal on Computing, 22(5):935–948, 1993. doi:10.1137/0222058.
  • [36] J. Ian Munro, Patrick K. Nicholson, Louisa Seelbach Benkner, and Sebastian Wild. Hypersuccinct trees - new universal tree source codes for optimal compressed tree data structures and range minima. In 29th Annual European Symposium on Algorithms, ESA 2021, September 6-8, 2021, Lisbon, Portugal (Virtual Conference), volume 204 of LIPIcs, pages 70:1–70:18. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2021. doi:10.4230/LIPIcs.ESA.2021.70.
  • [37] J. Ian Munro and Venkatesh Raman. Succinct representation of balanced parentheses and static trees. SIAM Journal on Computing, 31(3):762–776, 2002. doi:10.1137/S0097539799364092.
  • [38] Gonzalo Navarro. Indexing highly repetitive string collections, part I: repetitiveness measures. ACM Comput. Surv., 54(2):29:1–29:31, 2022. doi:10.1145/3434399.
  • [39] Gonzalo Navarro and Kunihiko Sadakane. Fully functional static and dynamic succinct trees. ACM Trans. Algorithms, 10(3), 2014. doi:10.1145/2601073.
  • [40] Mihai Patrascu. Succincter. In Proceedings of the 2008 49th Annual IEEE Symposium on Foundations of Computer Science, FOCS ’08, pages 305–313, USA, 2008. IEEE Computer Society. doi:10.1109/FOCS.2008.83.
  • [41] Rajeev Raman, Venkatesh Raman, and Srinivasa Rao Satti. Succinct indexable dictionaries with applications to encoding k-ary trees, prefix sums and multisets. ACM Trans. Algorithms, 3(4):43–es, November 2007. doi:10.1145/1290672.1290680.
  • [42] Kunihiko Sadakane. Compressed suffix trees with full functionality. Theor. Comp. Sys., 41(4):589–607, December 2007. doi:10.1007/s00224-006-1198-x.
  • [43] Sergey Slotin. Algorithms for modern hardware, 2021. Accessed on February 2, 2026. URL: https://en.algorithmica.org/hpc/algorithms/argmin/.
  • [44] Sebastiano Vigna. Broadword implementation of rank/select queries. In International Workshop on Experimental and Efficient Algorithms, pages 154–168. Springer, 2008. doi:10.1007/978-3-540-68552-4_12.

Appendix A Missing Proofs

Proof of Lemma 3.

The Lemma follows from Definition 2. Let u be the root of the node corresponding to position i in B. Let j=find_close(B,i), then the interval B[i+1,j1] encompasses the whole sequence BP(u.). After position j follows the sequence BP(u.r), which is therefore completely contained in the range B[j+1,enclose)(j)1]. Combining these observations, our claim follows.

Proof of Lemma 4.

By contradiction, suppose that LCP[i]=2 but the subtrees at SA[i] and SA[i1] are different. Since LCP[i]=2 and =subtree_size(B,SA[i]), the two subtrees must have different sizes. The only possibility is that subtree_size(B,SA[i1])>2.

Consider the parentheses at positions B[SA[i]+2] and B[SA[i1]+2]. Notice that if SA[i]+2>n, then the two subtrees are different only if LCP[i]<2, which is a contradiction.

If both B[SA[i]+2] and B[SA[i1]+2] are opening parentheses or both are closing parentheses, then LCP[i]>2, another contradiction.

Since B[SA[i1],n]B[SA[i],n], the only remaining case is that B[SA[i1]+2]=) and B[SA[i]+2]=(. However, because the substring B[SA[i],SA[i]+21] encodes a complete subtree, the closing parenthesis at position SA[i1]+2 must have been matched before to have a valid balanced parentheses sequence. Consequently, the only possibility is to have LCP[i]<2, which is again a contradiction.

Lemma 5.

For any binary tree of n nodes, the length of the longest chain of copies L in its minimal DAG is O(n) in the worst case.

Proof.

Let L1 denote the length of the longest chain of copies in the minimal DAG of the given tree. Let c1,c2,,cL1 be the copied subtrees in such a chain, from left to right following their appearance in the tree, and let ni be the number of nodes in the i-th copy.

We first observe that for every 1iL2, when moving from copy ci to ci+1, the size of ci+1 must be at most ni1 (note that it cannot exceed ni); otherwise, the chain would terminate earlier and thus have length strictly smaller than L. Consequently, the value of L is maximized when ni+1=ni1 for all 1iL2.

Assume that n1=m for some integer m2. Under the above condition, the longest possible chain consists of copies of sizes n2=m1,n3=m2,,nL1=2 (according to Section 3 leaves are not copied). It follows that L=m1, and that the total number of nodes contained in all copies along the chain is i=1L1ni=i=2mi=m(m+1)/21.

Since the total number of nodes in the tree is n, we must have nm(m+1)/21. Solving for m gives m=O(n), which concludes the proof as L=O(n).

Appendix B Missing Algorithms

As anticipated in Section 4.3, below we give a complete description of how the rank0 and select0 operations are computed using our representation.

B.1 select𝟎

To answer select0(B,i) queries on our compressed representation, we begin by introducing the following auxiliary function to compute the size (number of nodes) of any copied subtree.

copy_size(j)={(select1(S,2j)select1(S,2j1)+1)/2,if jp,0,otherwise.

Next, we determine whether the result of select0(B,i) lies within a copied subtree. To this end, we exploit the array N, which stores the inorder numbers (i.e., rank0 values) of the rightmost child of each copied subtree (recall Section 4.3). We first locate, via binary search, the predecessor of i in N, that is, the largest index j such that N[j]i, and distinguish between the following two cases:

  1. 1.

    if j=p or iN[j+1]copy_size(j+1), then the answer to select0(B,i) lies outside of a copied subtree. In this case, (iN[j]) gives the number of zeros between the j-th copy and the position that we are looking for. rank0(Bc,select1(R,j))+1 gives the number of zeros up to the j-th copy (included) in the compressed balanced parentheses. Therefore, k=rank0(Bc,select1(R,j))+1+(iN[j]), corresponds to the number of zeros in Bc before ϕ(select0(B,i)). Hence, the final result is given by select1(S,2j)+(select0(Bc,k)select1(R,j)).

  2. 2.

    Otherwise, the answer to select0(B,i) is contained inside the (j+1)-th copied subtree. Intuitively, we need to scale i to a valid value in the (j+1)-th copy, and then proceed recursively until reaching the previous base case. To this end, it is sufficient to compute the number of zeros from the beginning of the (j+1)-th copy and position select0(B,i), which is given by r=copy_size(j+1)(N[j+1]i). Therefore, we proceed recursively by searching for i=r+rank0(B,P[j+1]). In the following, we show that rank0(B,P[j+1]) can be computed without further recursive calls (see Algorithm 3). Let s=select0(B,i) be the result returned by the recursive call. To obtain the answer to the original query, we map k back to a valid position inside the (j+1)-th copy as select1(S,2j+1)+(sP[j+1]).

Considering the cost of our procedure, every recursive call takes O(logn) time, and since the number of such calls is proportional to the length of the longest chain of copies L, the overall cost is O(Llogn). The whole procedure is summarized in Algorithm 2.

Algorithm 2 select0(B,i) computation on our compressed representation.

B.2 rank𝟎

To answer rank0(B,i) queries on our representation, it is sufficient to notice that, because of the samples of rank0 on B that are stored in the N-array (recall section 4.3), we can distinguish between two simple cases. Let r=rank1(S,i), then:

  1. 1.

    If r is even (i.e., i lies outside a copied subtree), then the answer is computed by taking the number of zeros up to the previous pointer (assume N[0]=0) and adding the number of zeros between that pointer and i, computed directly on Bc. More precisely, the result is N[r/2]+(rank0(Bc,ϕ(i))rank0(Bc,select1(R,r/2)+1)).

  2. 2.

    Otherwise, we properly scale the value of i into a position of its source i, and proceed recursively until reaching the previous base case. Let r be the result of the recursive call, that is, r=rank0(B,i), and let j be the copy preceding position P[j] (if any). We compute the number of zeros between i and the beginning of the source of i (i.e., P[j]) as r(N[j]+(rank0(Bc,ϕ(P[j]))rank0(Bc,select1(R,j)+1))). The final result is obtained by summing the previous quantity to the number of zeros up to the beginning of the j-th copy, i.e., N[j]copy_size(j).

Algorithm 3 rank0(B,i) computation on our compressed representation.

Similarly to Algorithm 2, every recursive call takes O(logn) time, and the number of such calls is bounded by the length of the longest chain of copies L. Therefore, the overall cost is O(Llogn). The whole procedure is summarized in Algorithm 3.

Appendix C Complete Experimental Results

We report the experimental results on the missing datasets described in Section 5.

Figure 4: Effectiveness of the top-level sparse table described in Section 5.1 on the missing datasets of Section 5.3. For each range size on the x-axis, the percentage of queries that are immediately solved with the sparse table is reported on the y-axis.
Figure 5: Space-time performance on the LCPs of texts from the Pizza & Chili corpus that were not presented in Section 5.3. Missing solutions in some plots indicate that we were not able to run them on those specific instances.