Abstract 1 Introduction 2 Preliminaries 3 Hybrid Bitvector 4 Select Queries on a Hybrid Bitvector 5 Experimental Results References

Fast Select Queries Using Hybrid Bitvectors

Eric Chiu ORCID Department of Computer Science, Stony Brook University, NY, USA    Dominik Kempa ORCID Department of Computer Science, Stony Brook University, NY, USA
Abstract

One of the central problems in the design of compressed data structures is the efficient support for rank and select queries on bitvectors. These two operations form the backbone of more complex data structures used for the compact representation of texts, trees, graphs, or grids. One effective solution is the so-called hybrid bitvector implementation, which partitions the input bitvector into blocks and adaptively selects an encoding method – such as run-length, plain, or minority encoding – based on local redundancy. Experiments have shown that hybrid bitvectors achieve excellent all-around performance on repetitive and non-repetitive inputs. Current hybrid bitvector implementations, however, support only rank queries (i.e., counting the number of ones up to a given position) and lack support for select queries (which ask for the position of a given occurrence of a given bit), which limits their applicability. In this paper, we propose a method to add support for select queries to hybrid bitvectors, and we evaluate the resulting implementation on repetitive and non-repetitive inputs. Our results show that hybrid bitvectors offer very strong all-around performance, combining high query speed with space efficiency and remaining consistently on or near the Pareto frontier.

Keywords and phrases:
compressed bitvectors, hybrid bitvector, select queries
Copyright and License:
[Uncaptioned image] © Eric Chiu and Dominik Kempa; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation Design and analysis of algorithms
; Theory of computation Data compression ; Information systems Information retrieval
Related Version:
Full Version: https://arxiv.org/abs/2509.06900
Supplementary Material:
Software: https://github.com/echiu12/hyb-vector
Funding:
Partially funded by the NSF CAREER Award 2337891.
Editors:
Martin Aumüller and Irene Finocchi

1 Introduction

Despite the increasing storage capacities of modern systems, storing and searching large datasets in many applications, such as bioinformatics [5, 29], remains a challenge. One way to keep up with these demands is through the use of compressed data structures. The performance of such data structures often depends on the efficiency of a small number of basic components. One such component is the bitvector with support for rank and select queries [22]. These operations are used in many compressed data structures, including FM-indexes, wavelet trees, and compressed suffix trees [8, 15, 27, 9, 1, 18, 11]. A plain bitvector with constant-time rank and select support uses n+o(n) bits [21], while compressed bitvectors can support the same operations in less space [25, 24]. There are several ways to compress a bitvector, but no single method is best for all inputs. For example, the SD bitvector [23] is effective when the number of one bits is small, and run-length-based representations are effective when the number of runs is small [28]. In practice, a bitvector may contain regions with different local structure [16].

One way of dealing with such local variability is the hybrid bitvector encoding introduced by Kärkkäinen et al. [16]. It partitions the bitvector into blocks and chooses, for each block, the most space-efficient representation among several alternatives. Their experiments showed that this approach gives very good overall performance in FM-indexes on both repetitive and non-repetitive texts. However, available implementations of the hybrid bitvector do not support select queries, which limits their applications.

In this paper, we describe how to add select support to the hybrid bitvector. We evaluate the resulting implementation on repetitive and non-repetitive texts and compare it with existing bitvector implementations that support select. The results show that the hybrid bitvector offers very strong all-around select-query performance across different types of data, both repetitive and non-repetitive, remaining consistently on or near the Pareto frontier.

2 Preliminaries

For a string SΣn of length n over alphabet Σ, we denote the ith symbol of S by S[i], where i[1..n]. A substring S[i]S[i+1]S[j], where 1ijn, is denoted by S[i..j]. We use (i..j], (i..j), and [i..j) as shorthands for [i+1..j], [i+1..j1], and [i..j1], respectively. A substring S[i..j] is a prefix (resp. suffix) of S if i=1 (resp. j=n). Given strings S1 and S2, we denote their concatenation by S1S2 or S1S2. In this paper, we typically assume that Σ=[0..σ), where σ2. The case σ=2 corresponds to a bitvector, which we typically denote by B{𝟶,𝟷}n.

Rank query:

Let SΣn. For every i[0..n] and every cΣ, we define rankS(i,c):=|{j[1..i]:S[j]=c}|, i.e., rankS(i,c) is the number of occurrences of symbol c in the prefix S[1..i]. For example, if S=abacaa, then rankS(4,a)=2 and rankS(5,a)=3.

Select query:

Let SΣn. For every cΣ and every r[1..rankS(n,c)], we define selectS(r,c) as the rth smallest element of the set {j[1..n]:S[j]=c}. For example, if S=abacaa, then selectS(2,a)=3 and selectS(3,a)=5.

3 Hybrid Bitvector

In this section, we describe the components of the hybrid bitvector [16] and introduce the notation necessary to describe our augmentations to support select queries.

Definitions.

Consider a bitvector B{𝟶,𝟷}n. The basic idea of the hybrid bitvector is to split the bitvector B into blocks of size b=256 and encode each block independently, choosing the most space-efficient of the following three encodings:

  1. 1.

    Minority encoding: a list of all occurrences of the rarely occurring bit c{0,1}.

  2. 2.

    Run-length encoding: a list of positions marking the ends of maximal runs of equal bits.

  3. 3.

    Plain encoding: all bits stored sequentially using b bits.

For any bitvector B, let enclen(B) denote the total size of the encoding (in bytes) of B after splitting it into blocks of size b and independently encoding each using the smallest of the three methods listed above. By popcount(B) we denote the number of ones in B.

In the hybrid encoding of the bitvector B, the blocks are further grouped into superblocks of ks blocks (that is, ksb bits) and into hyperblocks of kh blocks (that is, khb bits). The value ks is a parameter of the hybrid bitvector; the default value in the implementation is ks=16. The number of blocks per hyperblock is fixed at kh=223.

Table 1: Definitions of functions describing hybrid bitvector components.
Function Definition
hblockB(i) B(khb(i1)..khbi]
hblockrankB,c(i) rankB(khb(i1),c)
hblockoffsetB(i) enclen(B[1..khb(i1)])
sblockB(i) B(ksb(i1)..ksbi]
sblockrankB,c(i) rankB(ksb(i1),c)hblockrankB,c(ks(i1)kh+1)
sblockoffsetB(i) enclen(B[1..ksb(i1)])hblockoffsetB(ks(i1)kh+1)
blockB(i) B(b(i1)..bi]
blockrankB,c(i) rankB(b(i1),c)hblockrankB,c(i1kh+1)sblockrankB,c(i1ks+1)
blockoffsetB(i) enclen(B[1..b(i1)])hblockoffsetB(i1kh+1)sblockoffsetB(i1ks+1)
blockonesB(i) popcount(blockB(i))
blockenclenB(i) enclen(blockB(i))

By blockB(i), sblockB(i), and hblockB(i) we denote the ith block, the ith superblock, and the ith hyperblock of B, respectively. By blockrankB,c(i), we denote the number of cs in the superblock of B containing blockB(i) prior to its beginning. Similarly, by sblockrankB,c(i), we denote the number of cs in the hyperblock of B containing sblockB(i) prior to its beginning. Finally, by hblockrankB,c(i), we denote the number of cs prior to the beginning of hblockB(i) in B. By blockoffsetB(i), we denote the total encoding size of all blocks in the superblock containing blockB(i) that are to its left. Similarly, by sblockoffsetB(i), we denote the total encoding size of all blocks in the hyperblock containing sblockB(i) that are to its left. Finally, by hblockoffsetB(i), we denote the total encoding size of blocks that are to the left of hblockB(i) in B. See Table 1 for formal definitions.

Components.

The hybrid bitvector consists of the following three components:

  1. 1.

    an array of hyperblock headers AH,

  2. 2.

    an array of superblock and block headers AS, and

  3. 3.

    an array of variable-sized block encodings AE.

The ith hyperblock header gives context for the hyperblock hblockB(i) and contains (1) hblockrankB,1(i), and (2) hblockoffsetB(i).

The array AS contains both superblock headers and block headers. It is organized so that each superblock header is followed by the ks block headers for blocks inside that superblock. The ith superblock header gives context for sblockB(i) and contains: (1) sblockrankB,1(i), (2) sblockoffsetB(i), and (3) a flag indicating whether the superblock is uniform (i.e., it contains only zeroes or ones). The ith block header describes blockB(i) and contains: (1) blockonesB(i), (2) blockenclenB(i), and (3) specialbitB(i), a special bit that gives additional information about the encoding. The specialbitB(i) is interpreted differently for each encoding. For the minority encoding, specialbitB(i) identifies the minority bit. For the run-length encoding, it identifies the first bit of that block. For the plain encoding, it is ignored. Note that blockrankB,1(i) and blockoffsetB(i) are not stored, but they can be computed as the sums of blockonesB() and blockenclenB() over preceding blocks (in the same superblock).

Block encodings are concatenated to form the array AE. The encoding for the ith block is located at offset hblockoffsetB(i1kh+1)+sblockoffsetB(i1ks+1)+blockoffsetB(i) with length blockenclenB(i). The encoding type of the ith block can be identified from blockenclenB(i) together with blockonesB(i). If blockenclenB(i)=b8, then the block uses plain encoding. Otherwise, if blockenclenB(i)=min{blockonesB(i),bblockonesB(i)}, then the block is minority encoded. In all remaining cases, it is run-length encoded.

Run-Length Encoding Optimization.

To save space, the run-length encoding in the hybrid bitvector does not list the last two run endings; instead, they can be recovered from the stored run endings together with the block headers. More specifically, suppose that the ith block in B is run-length encoded, with all but the last two run endings stored as (r1,r2,,rm2). That is, there are m=blockenclenB(i)+2 maximal runs in blockB(i). On the other hand, we know rm=b and the set of run endings for runs containing 1-bits is D={x[1..m]:(x+specialbitB(i)) is even}. Using all this information, we can compute rm1 by solving the equation dD(rdrd1)=blockonesB(i) (where r0=0). Hence, we are able to recover the full run-length encoding (r1,r2,,rm) from the stored run endings (r1,r2,,rm2) and the block headers.

4 Select Queries on a Hybrid Bitvector

In this section, we describe how we implement select queries on the hybrid bitvector. Our goal is to compute selectB(q,c) for a bitvector B{0,1}n and target bit c{0,1}.

Definitions.

We use one parameter to control the space overhead of our select data structure. Let ρ denote this parameter; in our implementation, we set ρ=128. Further, let τ denote the sampling period between consecutive sampled c-bits. We choose τ to be the smallest positive integer such that sampling every τth c-bit yields at most max{n/(64ρ),2} sampled positions. We store these samples in a lookup table Ls as follows: for every integer j0 with jτ<rankB(n,c), the entry Ls[j+1] is the index of the superblock containing the (jτ+1)th c-bit in B, and the final entry is a sentinel equal to n/(ksb), i.e., the index of the last superblock. Since each entry of Ls is a 64-bit superblock index and the number of entries is bounded as above, the table uses about n/ρ bits in practice.

Components.

To support select queries on the hybrid bitvector, we augment it with the following two components:

  1. 1.

    the sampling period τ, and

  2. 2.

    the lookup table Ls.

Answering Queries.

To compute selectB(q,c), we proceed as follows:

  1. 1.

    Identify the superblock. First, we use the array Ls to narrow the search to a short interval of superblocks. We compute u:=(q1)/τ+1, is:=Ls[u], and is′′:=Ls[u+1]. By construction, the superblock containing the qth c-bit lies between these two indices, that is, isisis′′. We then locate the exact superblock index is by binary search in [is..is′′], where is=max{x[is..is′′]:hblockrankB,c(ks(x1)kh+1)+sblockrankB,c(x)<q}.

  2. 2.

    Recover the superblock context. Once is is known, the hyperblock containing it is immediate. Let ih=ks(is1)kh+1. From the corresponding hyperblock and superblock headers, we obtain the number of c-bits preceding sblockB(is), namely hblockrankB,c(ih)+sblockrankB,c(is), as well as the offset hblockoffsetB(ih)+sblockoffsetB(is) of the block encodings belonging to that superblock in AE.

  3. 3.

    Handle the uniform-superblock case. If the uniform-superblock flag is set, then every bit in sblockB(is) is equal, and the answer is obtained immediately from the beginning of the superblock and the local offset of the queried occurrence inside it. In this case, the array AE is not accessed.

  4. 4.

    Identify the block and the local query index. Otherwise, we scan the ks block headers that follow the superblock header in AS from left to right until we reach the block blockB(ib) containing the qth c-bit. During this scan, we compute both blockrankB,c(ib) and blockoffsetB(ib) as sums over the preceding blocks in the same superblock. We then define the local query index inside blockB(ib) by q=qhblockrankB,c(ih)sblockrankB,c(is)blockrankB,c(ib). Thus, q is the rank of the queried occurrence inside blockB(ib), and the encoding of blockB(ib) begins at offset hblockoffsetB(ih)+sblockoffsetB(is)+blockoffsetB(ib) in AE.

  5. 5.

    Answer the query inside the block. Let B=blockB(ib). We now compute selectB(q,c) according to the encoding type of B:

    • If B is minority encoded and c=specialbitB(ib), then the block encoding already stores the positions of all c-bits in the block, so selectB(q,c) is simply the qth stored position. Otherwise, the block encoding stores the positions of the opposite bit, and we scan these positions until we determine how many opposite bits occur before the qth c-bit; this lets us recover selectB(q,c) from the corresponding gap.

    • If B is plain encoded, we scan its 64-bit words from left to right, using hardware-supported bit-counting instructions to skip whole words until the answer lies in the current word, and then continue inside that word bit by bit.

    • If B is run-length encoded and blockenclenB(ib)=0, then the block contains at most two runs. In this case, selectB(q,c) follows immediately from specialbitB(ib) and the length of the first run, which is determined by blockonesB(ib). If B is run-length encoded and blockenclenB(ib)>0, we process the stored run endings from left to right. If the first run contains c-bits, we first check whether the answer already lies in that run. Afterwards, we inspect the stored run endings in pairs, each pair describing one run of (1c)-bits followed by one run of c-bits. We subtract the lengths of whole c-runs until the queried occurrence falls into the current run. If all stored c-runs are exhausted, then the answer must lie in one of the last two runs, and its position is recovered using blockonesB(ib) together with the fact that the last two run endings are omitted from the encoding.

  6. 6.

    Return the position in B. Finally, we return (ib1)b+selectB(q,c).

5 Experimental Results

In this section, we present the results of our experimental evaluation of select queries using hybrid bitvectors. We demonstrate this in two applications: PLCP queries (Section 5.1) and BWT select queries (Section 5.2).

Setup.

We conducted the experiments on an Intel Core i7-1355U CPU with 12 MiB L3 cache, 32 GiB of RAM, and 64-bit Ubuntu Linux 22.04.5 (kernel 6.8.0-60). Our code was compiled with g++ 11.4.0 using the flags -DNDEBUG -msse4.2 -funroll-loops -O3. We measured time using std::chrono::high_resolution_clock and the size of data structures via serialization.

Datasets.

As in [16], in our experiments we used datasets from the Pizza&Chili corpus [10], including both the standard (https://pizzachili.dcc.uchile.cl/texts.html) and the highly repetitive (https://pizzachili.dcc.uchile.cl/repcorpus.html) files. Basic statistics of all files are shown in Table 2.

Table 2: Statistics of datasets used in our experiments, including alphabet size (σ), length in MiB (n/220), and the average length of BWT-run (n/r), a robust measure of repetitiveness [4, 17].
Name σ n/220 n/r
dna 16 200 1.63
proteins 25 200 1.93
english 225 200 2.91
sources 230 200 4.40
dblp.xml 96 200 7.09
para 5 410 27
cere 5 440 40
influenza 15 148 51
world_leaders 89 44 82
kernel 160 246 93

5.1 Experiment 1: PLCP Queries

Description.

For any length-n string S, the permuted LCP (PLCP) array [26] of S is a length-n array containing the values of the standard longest-common-prefix (LCP) array [20] permuted into text order. The fundamental property of the PLCP array is that it can be encoded using only 2n bits such that a random access query to any of its values reduces to a single select query [26]. The resulting encoding (also called the PLCP bitvector) is a widely used space-efficient replacement for the PLCP array used, e.g., in compressed suffix trees [27].

In our first experiment, we evaluate the performance of PLCP access queries via select queries on the PLCP bitvector using different bitvector encodings. For each text in our data set, we prepared 105 randomly selected text positions and measured the average PLCP access query time for each bitvector. We then plotted these timing results against the space usage of each of the tested bitvectors.

Implementations.

In our experiment, we used the following bitvector types:

  • BV: The default uncompressed bitvector from the SDSL library [12].

  • HYB: The hybrid bitvector [16] with our implementation of select queries as described in this paper. Our implementation extends the implementation from [16], which is part of the SDSL library [12]. In our experiments, we tested parameters ks{8,16,32,64}.

  • NH: The hybrid bitvector [16] from SDSL [12] with a naive implementation of select via binary search and rank queries [13]. We again tested ks{8,16,32,64}.

  • RRR: The RRR bitvector [25] from SDSL [12] with block size 15, 31, 63, and 127.

  • SD: The SD bitvector [23] from SDSL [12] based on the Elias–Fano encoding [6, 7].

  • OZ: The oz-vector representation described in [22] and implemented in [13].

  • PASTA: The uncompressed bitvector [30] from the PASTA-Toolbox [19].

  • LA: The la-vector [2, 3], which uses the approach based on piecewise linear approximation.

  • ZOM: The zombit bitvector implementation from [13].

PLCP Query Time and Space

Figure 1: Performance of PLCP bitvector select queries for various bitvector types on non-repetitive (left column) and repetitive (right column) texts. The query time is averaged over 105 queries, and the space is relative to the text size.

Results and Discussion.

The results of the experiment are presented in Figure 1. Across all texts, HYB is consistently one of the smallest and fastest bitvectors for PLCP queries. For example, compared to RRR, HYB achieves the same or smaller space usage while being 2 to 3 times faster. Compared to NH (a naive implementation of select queries on the hybrid bitvector via rank queries and binary search), HYB uses essentially the same space and is simultaneously 3–4 times faster, which shows the effectiveness of the native select implementation and the negligible effect of the additional lookup table on space usage. Importantly, while some bitvector implementations achieve good performance on some files (e.g., PASTA performs very well on non-repetitive files, but uses notably more space on highly repetitive files; similarly, OZ performs best on dblp.xml, but its space is significantly larger on the proteins file), HYB performs well regardless of whether the text is non-repetitive or repetitive.

5.2 Experiment 2: BWT Select Queries

Description.

For any string SΣn such that S[n] is unique in S and is the smallest symbol in Σ, we define the Burrows–Wheeler Transform (BWT) as the permutation of symbols of S obtained by lexicographically sorting all n rotations of S and taking the last column of the resulting matrix [4]. BWT is a fundamental concept in data compression and text indexing. For example, it is the central component of the FM-Index [8].

In the second experiment, we evaluate the performance of select queries on the Burrows–Wheeler Transform (BWT) of the files in our dataset. To reduce select queries over arbitrary strings to select queries over bitvectors, we use wavelet trees [14]. For each text in our data set, we computed its BWT and then constructed the wavelet tree for the BWT, instantiated with different bitvector implementations. We then prepared 105 random arguments for select queries over the BWT and measured the average time for select queries and the space usage of the resulting wavelet tree.

BWT Select Query Time and Space

Figure 2: Performance of BWT select queries for various wavelet tree and bitvector types on non-repetitive (left column) and repetitive (right column) texts. The query time is averaged over 105 queries, and the space is relative to the text size.

Implementations.

In our experiments, we used wavelet tree implementations from the SDSL library [12]. Specifically, we used the two common variants: the balanced wavelet tree (denoted BLCD) and the Huffman-shaped wavelet tree (denoted HUFF) [14]. The underlying bitvector implementations are the same as in the previous experiment, with the exception of LA, which exceeded the RAM capacity of our machine during construction.

Results and Discussion.

The results of the experiment are presented in Figure 2. As in the previous experiment, most other bitvector implementations have an input regime in which performance deteriorates, whereas HYB variants of wavelet trees consistently offer strong performance on both non-repetitive and highly repetitive strings and, in all cases, contribute to or are very close to the Pareto frontier.

References

  • [1] Djamal Belazzougui and Gonzalo Navarro. Alphabet-independent compressed text indexing. ACM Transactions on Algorithms, 10(4):23:1–23:19, 2014. doi:10.1145/2635816.
  • [2] Antonio Boffa, Paolo Ferragina, and Giorgio Vinciguerra. A “learned” approach to quicken and compress rank/select dictionaries. In Proceedings of the 2021 SIAM Symposium on Algorithm Engineering and Experiments (ALENEX 2021), pages 46–59, 2021. doi:10.1137/1.9781611976472.4.
  • [3] Antonio Boffa, Paolo Ferragina, and Giorgio Vinciguerra. A learned approach to design compressed rank/select data structures. ACM Transactions on Algorithms, 2022. doi:10.1145/3524060.
  • [4] Michael Burrows. A block-sorting lossless data compression algorithm. SRS Research Report, 124, 1994.
  • [5] Laura Clarke, Xiangqun Zheng-Bradley, Richard Smith, Eugene Kulesha, Chunlin Xiao, Iliana Toneva, Brendan Vaughan, Don Preuss, Rasko Leinonen, Martin Shumway, et al. The 1000 genomes project: data management and community access. Nature Methods, 9(5):459–462, 2012. doi:10.1038/nmeth.1974.
  • [6] Peter Elias. Efficient storage and retrieval by content and address of static files. Journal of the ACM, 21(2):246–260, 1974. doi:10.1145/321812.321820.
  • [7] Robert M. Fano. On the Number of Bits Required to Implement an Associative Memory. MIT Project MAC Computer Structures Group, 1971.
  • [8] Paolo Ferragina and Giovanni Manzini. Indexing compressed text. Journal of the ACM, 52(4):552–581, 2005. doi:10.1145/1082036.1082039.
  • [9] Paolo Ferragina, Giovanni Manzini, Veli Mäkinen, and Gonzalo Navarro. An alphabet-friendly FM-index. In Proceedings of the 11th International Conference on String Processing and Information Retrieval (SPIRE 2004), pages 150–160. Springer, 2004. doi:10.1007/978-3-540-30213-1_23.
  • [10] Paolo Ferragina and Gonzalo Navarro. Pizza&Chili Corpus: Compressed Indexes and their Testbeds. URL: https://pizzachili.dcc.uchile.cl/.
  • [11] Johannes Fischer. Wee LCP. Information Processing Letters, 110(8-9):317–320, 2010. doi:10.1016/J.IPL.2010.02.010.
  • [12] Simon Gog, Timo Beller, Alistair Moffat, and Matthias Petri. From theory to practice: Plug and play with succinct data structures. In Proceedings of the 13th International Symposium on Experimental Algorithms (SEA 2014), pages 326–337. Springer, 2014. doi:10.1007/978-3-319-07959-2_28.
  • [13] Adrián Gómez-Brandón. Zombit: Exploiting runs in bitvectors. Software: Practice and Experience, 55(12):1975–1992, 2025. doi:10.1002/SPE.70019.
  • [14] Roberto Grossi, Ankur Gupta, and Jeffrey Scott Vitter. High-order entropy-compressed text indexes. In Proceedings of the 14th Annual ACM-SIAM Symposium on Discrete Algorithms (SODA 2003), pages 841–850. ACM/SIAM, 2003. URL: http://dl.acm.org/citation.cfm?id=644108.644250.
  • [15] Roberto Grossi and Jeffrey Scott Vitter. Compressed suffix arrays and suffix trees with applications to text indexing and string matching. SIAM Journal on Computing, 35(2):378–407, 2005. doi:10.1137/S0097539702402354.
  • [16] Juha Kärkkäinen, Dominik Kempa, and Simon J. Puglisi. Hybrid compression of bitvectors for the FM-index. In Proceedings of the 2014 Data Compression Conference (DCC 2014), pages 302–311. IEEE, 2014. doi:10.1109/DCC.2014.87.
  • [17] Dominik Kempa and Tomasz Kociumaka. Resolution of the Burrows-Wheeler transform conjecture. In Sandy Irani, editor, Proceedings of the 61st IEEE Annual Symposium on Foundations of Computer Science (FOCS 2020), pages 1002–1013. IEEE, 2020. doi:10.1109/FOCS46700.2020.00097.
  • [18] Dominik Kempa and Tomasz Kociumaka. Breaking the O(n)-barrier in the construction of compressed suffix arrays and suffix trees. In Proceedings of the 2023 ACM-SIAM Symposium on Discrete Algorithms (SODA 2023), pages 5122–5202. SIAM, 2023. doi:10.1137/1.9781611977554.CH187.
  • [19] Florian Kurpicz. Engineering compact data structures for rank and select queries on bit vectors. In Proceedings of the 29th International Symposium on String Processing and Information Retrieval (SPIRE 2022), pages 257–272. Springer, 2022. doi:10.1007/978-3-031-20643-6_19.
  • [20] Udi Manber and Eugene W. Myers. Suffix arrays: A new method for on-line string searches. SIAM Journal on Computing, 22(5):935–948, 1993. doi:10.1137/0222058.
  • [21] J. Ian Munro. Tables. In Proceedings of the 16th Conference on Foundations of Software Technology and Theoretical Computer Science (FSTTCS 1996), pages 37–42. Springer, 1996. doi:10.1007/3-540-62034-6_35.
  • [22] Gonzalo Navarro. Compact data structures: A practical approach. Cambridge University Press, Cambridge, UK, 2016. doi:10.1017/cbo9781316588284.
  • [23] Daisuke Okanohara and Kunihiko Sadakane. Practical entropy-compressed rank/select dictionary. In Proceedings of the Ninth Workshop on Algorithm Engineering and Experiments (ALENEX 2007). SIAM, 2007. doi:10.1137/1.9781611972870.6.
  • [24] Mihai Pătraşcu. Succincter. In Proceedings of the 49th Annual IEEE Symposium on Foundations of Computer Science (FOCS 2008), pages 305–313. IEEE Computer Society, 2008. doi:10.1109/FOCS.2008.83.
  • [25] Rajeev Raman, Venkatesh Raman, and Srinivasa Rao Satti. Succinct indexable dictionaries with applications to encoding k-ary trees, prefix sums and multisets. ACM Transactions on Algorithms, 3(4):43, 2007. doi:10.1145/1290672.1290680.
  • [26] Kunihiko Sadakane. Succinct representations of lcp information and improvements in the compressed suffix arrays. In Proceedings of the 13th Annual ACM-SIAM Symposium on Discrete Algorithms (SODA 2002), pages 225–232. ACM/SIAM, 2002. URL: http://dl.acm.org/citation.cfm?id=545381.545410.
  • [27] Kunihiko Sadakane. Compressed suffix trees with full functionality. Theory of Computing Systems, 41(4):589–607, 2007. doi:10.1007/S00224-006-1198-X.
  • [28] Jouni Sirén, Niko Välimäki, Veli Mäkinen, and Gonzalo Navarro. Run-length compressed indexes are superior for highly repetitive sequence collections. In Proceedings of the 15th International Symposium on String Processing and Information Retrieval (SPIRE 2008), pages 164–175. Springer, 2008. doi:10.1007/978-3-540-89097-3_17.
  • [29] Clare Turnbull, Richard H Scott, Ellen Thomas, Louise Jones, Nirupa Murugaesu, Freya Boardman Pretty, Dina Halai, Emma Baple, Clare Craig, Angela Hamblin, et al. The 100000 genomes project: bringing whole genome sequencing to the NHS. BMJ, 361, 2018. doi:10.1136/bmj.k1687.
  • [30] Dong Zhou, David G. Andersen, and Michael Kaminsky. Space-efficient, high-performance rank and select structures on uncompressed bit sequences. In Vincenzo Bonifaci, Camil Demetrescu, and Alberto Marchetti-Spaccamela, editors, Proceedings of the 12th International Symposium on Experimental Algorithms (SEA 2013), pages 151–163. Springer, 2013. doi:10.1007/978-3-642-38527-8_15.