On this page
article
SegTree Esparsa - O(q) memoria
Sobre
Query: min do range [a, b]
Update: troca o valor de uma posicao
Usa O(q) de memoria para q updates
Complexidades:
query - O(log(n))
update - O(log(n))
Link original: segTreeEsparsa2.cpp
Código
template<typename T> struct seg {
struct node {
node* ch[2];
char d;
T v;
T mi;
node(int d_, T v_, T val) : d(d_), v(v_) {
ch[0] = ch[1] = NULL;
mi = val;
}
node(node* x) : d(x->d), v(x->v), mi(x->mi) {
ch[0] = x->ch[0], ch[1] = x->ch[1];
}
void update() {
mi = numeric_limits<T>::max();
for (int i = 0; i < 2; i++) if (ch[i])
mi = min(mi, ch[i]->mi);
}
};
node* root;
char n;
seg() : root(NULL), n(0) {}
~seg() {
std::vector<node*> q = {root};
while (q.size()) {
node* x = q.back(); q.pop_back();
if (!x) continue;
q.push_back(x->ch[0]), q.push_back(x->ch[1]);
delete x;
}
}
char msb(T v, char l, char r) { // msb in range (l, r]
for (char i = r; i > l; i--) if (v>>i&1) return i;
return -1;
}
void cut(node* at, T v, char i) {
char d = msb(v ^ at->v, at->d, i);
if (d == -1) return; // no need to split
node* nxt = new node(at);
at->ch[v>>d&1] = NULL;
at->ch[!(v>>d&1)] = nxt;
at->d = d;
}
node* update(node* at, T idx, T val, char i) {
if (!at) return new node(-1, idx, val);
cut(at, idx, i);
if (at->d == -1) { // leaf
at->mi = val;
return at;
}
bool dir = idx>>at->d&1;
at->ch[dir] = update(at->ch[dir], idx, val, at->d-1);
at->update();
return at;
}
void update(T idx, T val) {
while (idx>>n) n++;
root = update(root, idx, val, n-1);
}
T query(node* at, T a, T b, T l, T r, char i) {
if (!at or b < l or r < a) return numeric_limits<T>::max();
if (a <= l and r <= b) return at->mi;
T m = l + (r-l)/2;
if (at->d < i) {
if ((at->v>>i&1) == 0) return query(at, a, b, l, m, i-1);
else return query(at, a, b, m+1, r, i-1);
}
return min(query(at->ch[0], a, b, l, m, i-1), query(at->ch[1], a, b, m+1, r, i-1));
}
T query(T l, T r) { return query(root, l, r, 0, (T(1)<<n)-1, n-1); }
};