On this page
article
SQRT Tree
Sobre
RMQ em O(log log n) com O(n log log n) pra buildar
Funciona com qualquer operacao associativa
Tao rapido quanto a sparse table, mas usa menos memoria
(log log (1e9) < 5, entao a query eh praticamente O(1))
build - O(n log log n)
query - O(log log n)
Link original: sqrtTree.cpp
Código
namespace sqrtTree {
int n, *v;
int pref[4][MAX], sulf[4][MAX], getl[4][MAX], entre[4][MAX], sz[4];
int op(int a, int b) { return min(a, b); }
inline int getblk(int p, int i) { return (i-getl[p][i])/sz[p]; }
void build(int p, int l, int r) {
if (l+1 >= r) return;
for (int i = l; i <= r; i++) getl[p][i] = l;
for (int L = l; L <= r; L += sz[p]) {
int R = min(L+sz[p]-1, r);
pref[p][L] = v[L], sulf[p][R] = v[R];
for (int i = L+1; i <= R; i++) pref[p][i] = op(pref[p][i-1], v[i]);
for (int i = R-1; i >= L; i--) sulf[p][i] = op(v[i], sulf[p][i+1]);
build(p+1, L, R);
}
for (int i = 0; i <= sz[p]; i++) {
int at = entre[p][l+i*sz[p]+i] = sulf[p][l+i*sz[p]];
for (int j = i+1; j <= sz[p]; j++) entre[p][l+i*sz[p]+j] = at =
op(at, sulf[p][l+j*sz[p]]);
}
}
void build(int n2, int* v2) {
n = n2, v = v2;
for (int p = 0; p < 4; p++) sz[p] = n2 = sqrt(n2);
build(0, 0, n-1);
}
int query(int l, int r) {
if (l+1 >= r) return l == r ? v[l] : op(v[l], v[r]);
int p = 0;
while (getblk(p, l) == getblk(p, r)) p++;
int ans = sulf[p][l], a = getblk(p, l)+1, b = getblk(p, r)-1;
if (a <= b) ans = op(ans, entre[p][getl[p][l]+a*sz[p]+b]);
return op(ans, pref[p][r]);
}
}