http://www.bio.ifi.lmu.de/forschung/succinct/
<http://www.gnu.org/licenses/>
#ifndef _RMQ_succinct_hpp_
#define _RMQ_succinct_hpp_
template <typename DT, typename DTidx>
class RMQ_succinct
{
public:
typedef unsigned char DTsucc;
typedef unsigned short DTsucc2;
DTidx query(DTidx, DTidx);
RMQ_succinct(const DT* a, DTidx n);
~RMQ_succinct()
{
if (ARRAY_VERY_SMALL) return;
delete[] type;
for (DTidx i = 0; i < Catalan(s,s); i++) delete[] Prec[i];
delete[] Prec;
for (DTidx i = 0; i < M_depth; i++) delete[] M[i];
delete[] M;
for (DTidx i = 0; i < Mprime_depth; i++) delete[] Mprime[i];
delete[] Mprime;
}
protected:
const DT *a;
DTidx n;
DTsucc** M;
inline DTidx m(DTidx k, DTidx block) { return M[k][block]+(block*sprime); }
DTidx M_depth;
DTidx** Mprime;
DTidx Mprime_depth;
DTsucc2 *type;
DTsucc** Prec;
DTidx s;
DTidx sprime;
DTidx sprimeprime;
DTidx nb;
DTidx nsb;
DTidx nmb;
inline DTidx microblock(DTidx i) { return i/s; }
inline DTidx block(DTidx i) { return i/sprime; }
inline DTidx superblock(DTidx i) { return i/sprimeprime; }
static inline DTidx Catalan(DTidx a, DTidx b)
{
static const DTidx catalan[17][17] = {
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
{0,0,2,5,9,14,20,27,35,44,54,65,77,90,104,119,135},
{0,0,0,5,14,28,48,75,110,154,208,273,350,440,544,663,798},
{0,0,0,0,14,42,90,165,275,429,637,910,1260,1700,2244,2907,3705},
{0,0,0,0,0,42,132,297,572,1001,1638,2548,3808,5508,7752,10659,14364},
{0,0,0,0,0,0,132,429,1001,2002,3640,6188,9996,15504,23256,33915,48279},
{0,0,0,0,0,0,0,429,1430,3432,7072,13260,23256,38760,62016,95931,144210},
{0,0,0,0,0,0,0,0,1430,4862,11934,25194,48450,87210,149226,245157,389367},
{0,0,0,0,0,0,0,0,0,4862,16796,41990,90440,177650,326876,572033,961400},
{0,0,0,0,0,0,0,0,0,0,16796,58786,149226,326876,653752,1225785,2187185},
{0,0,0,0,0,0,0,0,0,0,0,58786,208012,534888,1188640,2414425,4601610},
{0,0,0,0,0,0,0,0,0,0,0,0,208012,742900,1931540,4345965,8947575},
{0,0,0,0,0,0,0,0,0,0,0,0,0,742900,2674440,7020405,15967980},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,2674440,9694845,25662825},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9694845,35357670},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35357670}
};
return catalan[a][b];
}
static inline DTsucc clearbits(DTsucc n, DTidx x)
{
static const DTsucc HighestBitsSet[8] =
{ ~0, ~1, ~3, ~7, ~15, ~31, ~63, ~127 };
return n & HighestBitsSet[x];
}
static inline DTidx lsb(DTsucc v) {
static const char LSBTable256[256] = {
0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
};
return LSBTable256[v];
}
inline DTidx log2fast(DTidx v)
{
DTidx c = 0;
register DTidx t, tt;
static const char LogTable256[256] = {
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
};
if ((tt = v >> 16))
c = (t = v >> 24) ? 24 + LogTable256[t] : 16 + LogTable256[tt & 0xFF];
else
c = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
return c;
}
bool ARRAY_VERY_SMALL;
};
template <typename DT, typename DTidx>
RMQ_succinct<DT,DTidx>::RMQ_succinct(const DT* a, DTidx n)
{
this->a = a;
this->n = n;
s = 1 << 3;
sprime = 1 << 4;
sprimeprime = 1 << 8;
nb = block(n-1)+1;
nsb = superblock(n-1)+1;
nmb = microblock(n-1)+1;
ARRAY_VERY_SMALL = false;
if (nb<sprimeprime/(2*sprime)) { ARRAY_VERY_SMALL = true; return; }
type = new DTsucc2[nmb];
#ifdef MEM_COUNT
unsigned long mem = sizeof(DTsucc2)*nmb;
#endif
Prec = new DTsucc*[Catalan(s,s)];
for (DTidx i = 0; i < Catalan(s,s); i++) {
Prec[i] = new DTsucc[s];
#ifdef MEM_COUNT
mem += sizeof(DTsucc)*s;
#endif
Prec[i][0] = 1;
}
DT* rp = new DT[s+1];
DTidx z = 0;
DTidx start;
DTidx end;
DTidx q;
DTidx p;
rp[0] = std::numeric_limits<DT>::min();
DTidx* gstack = new DTidx[s];
DTidx gstacksize;
DTidx g;
for (DTidx i = 0; i < nmb; i++) {
start = z;
end = start + s;
if (end > n) end = n;
q = s;
p = s-1;
type[i] = 0;
rp[1] = a[z];
while (++z < end) {
p--;
while (rp[q-p-1] > a[z]) {
type[i] += Catalan(p,q);
q--;
}
rp[q-p] = a[z];
}
if (Prec[type[i]][0] == 1) {
Prec[type[i]][0] = 0;
gstacksize = 0;
for (DTidx j = start; j < end; j++) {
while(gstacksize > 0 && (a[j] < a[gstack[gstacksize-1]])) {
gstacksize--;
}
if(gstacksize > 0) {
g = gstack[gstacksize-1];
Prec[type[i]][j-start] = Prec[type[i]][g-start] | (1 << (g % s));
}
else Prec[type[i]][j-start] = 0;
gstack[gstacksize++] = j;
}
}
}
delete[] rp;
delete[] gstack;
M_depth = (DTidx) floor(log2(((double) sprimeprime / (double) sprime)));
M = new DTsucc*[M_depth];
M[0] = new DTsucc[nb];
#ifdef MEM_COUNT
mem += sizeof(DTsucc)*nb;
#endif
Mprime_depth = (DTidx) floor(log2(nsb)) + 1;
Mprime = new DTidx*[Mprime_depth];
Mprime[0] = new DTidx[nsb];
#ifdef MEM_COUNT
mem += sizeof(DTidx)*nsb;
#endif
z = 0;
q = 0;
g = 0;
for (DTidx i = 0; i < nb; i++) {
start = z;
p = start;
end = start + sprime;
if (end > n) end = n;
if (a[z] < a[q]) q = z;
while (++z < end) {
if (a[z] < a[p]) p = z;
if (a[z] < a[q]) q = z;
}
M[0][i] = p-start;
if (z % sprimeprime == 0 || z == n) {
Mprime[0][g++] = q;
q = z;
}
}
DTidx dist = 1;
for (DTidx j = 1; j < M_depth; j++) {
M[j] = new DTsucc[nb];
#ifdef MEM_COUNT
mem += sizeof(DTsucc)*nb;
#endif
for (DTidx i = 0; i < nb - dist; i++) {
M[j][i] = a[m(j-1, i)] <= a[m(j-1,i+dist)] ?
M[j-1][i] : M[j-1][i+dist] + (dist*sprime);
}
for (DTidx i = nb - dist; i < nb; i++) M[j][i] = M[j-1][i];
dist *= 2;
}
dist = 1;
for (DTidx j = 1; j < Mprime_depth; j++) {
Mprime[j] = new DTidx[nsb];
#ifdef MEM_COUNT
mem += sizeof(DTidx)*nsb;
#endif
for (DTidx i = 0; i < nsb - dist; i++) {
Mprime[j][i] = a[Mprime[j-1][i]] <= a[Mprime[j-1][i+dist]] ?
Mprime[j-1][i] : Mprime[j-1][i+dist];
}
for (DTidx i = nsb - dist; i < nsb; i++) Mprime[j][i] = Mprime[j-1][i];
dist *= 2;
}
#ifdef MEM_COUNT
std::cout << "allocated " << mem << " bytes\n";
#endif
}
template <typename DT, typename DTidx>
DTidx RMQ_succinct<DT,DTidx>::query(DTidx i, DTidx j)
{
DTidx mb_i = microblock(i);
DTidx mb_j = microblock(j);
DTidx min, min_tmp;
DTidx s_mi = mb_i * s;
DTidx i_pos = i - s_mi;
if (ARRAY_VERY_SMALL) {
min = i;
for (DTidx x = i+1; x <= j; x++) if (a[x] < a[min]) min = x;
}
else if (mb_i == mb_j) {
min_tmp = clearbits(Prec[type[mb_i]][j-s_mi], i_pos);
min = min_tmp == 0 ? j : s_mi + lsb(min_tmp);
}
else {
DTidx b_i = block(i);
DTidx b_j = block(j);
DTidx s_mj = mb_j * s;
DTidx j_pos = j - s_mj;
min_tmp = clearbits(Prec[type[mb_i]][s-1], i_pos);
min = min_tmp == 0 ? s_mi + s - 1 : s_mi + lsb(min_tmp);
if (mb_j > mb_i + 1) {
DTidx s_bi = b_i * sprime;
DTidx s_bj = b_j * sprime;
if (s_bi+s > i) {
mb_i++;
min_tmp = Prec[type[mb_i]][s-1] == 0 ?
s_bi + sprime - 1 : s_mi + s + lsb(Prec[type[mb_i]][s-1]);
if (a[min_tmp] < a[min]) min = min_tmp;
}
if (b_j > b_i + 1) {
DTidx k, t, b;
b_i++;
if (s_bj - s_bi - sprime <= sprimeprime) {
k = log2fast(b_j - b_i - 1);
t = 1 << k;
i = m(k, b_i); b = m(k, b_j-t);
min_tmp = a[i] <= a[b] ? i : b;
if (a[min_tmp] < a[min]) min = min_tmp;
}
else {
DTidx sb_i = superblock(i);
DTidx sb_j = superblock(j);
b = block((sb_i+1)*sprimeprime);
k = log2fast(b - b_i);
t = 1 << k;
i = m(k, b_i); i_pos = m(k, b+1-t);
min_tmp = a[i] <= a[i_pos] ? i : i_pos;
if (a[min_tmp] < a[min]) min = min_tmp;
if (sb_j > sb_i + 1) {
k = log2fast(sb_j - sb_i - 2);
t = 1 << k;
i = Mprime[k][sb_i+1]; i_pos = Mprime[k][sb_j-t];
min_tmp = a[i] <= a[i_pos] ? i : i_pos;
if (a[min_tmp] < a[min]) min = min_tmp;
}
b = block(sb_j*sprimeprime);
k = log2fast(b_j - b);
t = 1 << k;
b--;
i = m(k, b); i_pos = m(k, b_j-t);
min_tmp = a[i] <= a[i_pos] ? i : i_pos;
if (a[min_tmp] < a[min]) min = min_tmp;
}
}
if (j >= s_bj+s) {
min_tmp = Prec[type[mb_j-1]][s-1] == 0 ?
s_mj - 1 : s_bj + lsb(Prec[type[mb_j-1]][s-1]);
if (a[min_tmp] < a[min]) min = min_tmp;
}
}
min_tmp = Prec[type[mb_j]][j_pos] == 0 ?
j : s_mj + lsb(Prec[type[mb_j]][j_pos]);
if (a[min_tmp] < a[min]) min = min_tmp;
}
return min;
}
#endif