Growing Trees
Complejidad temporal:
Mantengamos un arreglo , que está ordenado por altura. Para responder una consulta de tipo C, podemos simplemente hacer búsqueda binaria sobre los extremos de la consulta.
Ahora, solo necesitamos soportar actualizaciones. Primero hagamos búsqueda binaria de la primera posición tal que . Sea . Solo hay que incrementar el rango en manteniendo ordenado.
Sin embargo, no podemos simplemente sumar a todos los elementos del rango porque esto podría romper el orden. Esto ocurre sii hay algún índice tal que ; si incrementamos el rango , entonces , que es una inversión.
Para evitar este error, hallamos otro rango tal que para todo ; esto se puede hallar con búsqueda binaria. Como todos los satisfacen , podemos incrementar primero. Luego, como hay que incrementar un total de elementos, nos quedan elementos. Incrementamos el rango en uno.
Nótese que esto no crea inversiones porque es mayor que antes de la actualización: después de la actualización, el arreglo quedaría no decreciente.
Las actualizaciones y consultas se pueden manejar con un árbol de segmentos perezoso, pero un árbol indexado binario alcanzaría ya que solo necesitamos consultas puntuales.
#include <bits/stdc++.h>
using namespace std;
#define N 100000
int n, q, a[N], bit[N];
void add(int l, int r, int x) { // add x to [l, r]
if (r < l) return;
for (; l < n; l |= l + 1) bit[l] += x;
for (++r; r < n; r |= r + 1) bit[r] -= x;
}
int query(int i) { // point query at i
int sum = 0;
for (; i >= 0; i &= i + 1, --i) sum += bit[i];
return sum;
}
/* from Benq */
template <class T, class U> T firstTrue(T lo, T hi, U f) {
assert(lo <= hi);
++hi; // assuming f is increasing
while (lo < hi) { // find first index such that f is true
T mid = lo + (hi - lo) / 2;
f(mid) ? hi = mid : lo = mid + 1;
}
return lo;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> q;
for (int i = 0; i < n; ++i) cin >> a[i];
sort(a, a + n);
for (int i = 0; i < n; ++i) add(i, i, a[i]);
for (int i = 0; i < q; ++i) {
char c;
int a, b;
cin >> c >> a >> b;
if (c == 'F') {
int l = firstTrue(0, n - 1, [&](int i) { return query(i) >= b; });
if (l == n) // found nothing
continue;
int r = l + a - 1;
if (r >= n - 1) {
add(l, n - 1, 1);
continue;
}
int x = query(r);
int l_ = firstTrue(l, n - 1, [&](int i) { return query(i) >= x; });
int r_ = firstTrue(l_, n - 1, [&](int i) { return query(i) > x; }) - 1;
add(l, l_ - 1, 1);
add(r_ - (a - (l_ - l)) + 1, r_, 1);
} else {
int l = firstTrue(0, n - 1, [&](int i) { return query(i) >= a; });
int r = firstTrue(0, n - 1, [&](int i) { return query(i) > b; });
cout << r - l << '\n';
}
}
}