Count the Trains
Explicación
Sea la velocidad máxima del vagón , y la velocidad a la que corre actualmente. Como el vagón nunca puede adelantar a los vagones que tiene delante, es el mínimo de prefijos . El arreglo es no creciente, y cada cambio de valor es un límite entre trenes. Así, en cualquier momento, la respuesta es el número de valores distintos en .
En lugar de guardar todo el arreglo de mínimos de prefijos, mantenemos un conjunto de índices de inicio, o los índices donde empieza un tren nuevo, que son el índice y cada índice donde . Observemos que en cualquier índice de inicio , así que la velocidad verdadera de una posición es , donde es el índice de inicio más cercano a la izquierda de .
Cuando una consulta disminuye , ocurre una de las siguientes:
- La velocidad verdadera , definida por un índice de inicio, es igual o más lenta que . Así, el conjunto de índices de inicio (es decir, el número de trenes) permanece igual.
- La velocidad verdadera anterior es mayor que , lo que hace que se convierta en un índice de inicio. Observemos que que se convierta en un índice de inicio puede hacer que algunos índices de inicio queden obsoletos. Para eliminar estos índices obsoletos, comprobamos de forma iterativa el índice de inicio más cercano a la derecha de , y vemos si su valor es mayor que . Si es así, lo borramos y seguimos comprobando índices.
En cada momento, el número de trenes es igual al número de índices de inicio. Tenemos a lo sumo inserciones de índices de inicio, y por lo tanto el número de eliminaciones de índices también está acotado por . Así, la complejidad temporal total se amortiza a .
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int test_num;
cin >> test_num;
for (int t = 0; t < test_num; ++t) {
int n, q;
cin >> n >> q;
vector<long long> a(n);
for (auto &x : a) { cin >> x; }
// Construir el conjunto inicial de índices de inicio de tren
vector<long long> pref_min(n);
pref_min[0] = a[0];
set<int> starts = {0};
for (int i = 1; i < n; i++) {
pref_min[i] = min(pref_min[i - 1], a[i]);
if (pref_min[i] < pref_min[i - 1]) { starts.insert(i); }
}
while (q--) {
int k;
long long d;
cin >> k >> d;
k--;
// El mayor índice de inicio <= k determina la velocidad verdadera actual del vagón k
int j = *prev(starts.upper_bound(k));
long long cur_speed = a[j];
a[k] -= d;
if (a[k] >= cur_speed) {
cout << starts.size() << ' ';
continue;
}
starts.insert(k);
// Borrar todo índice de inicio posterior dominado por la nueva velocidad más baja
auto it = next(starts.find(k));
while (it != starts.end() && a[*it] >= a[k]) { it = starts.erase(it); }
cout << starts.size() << ' ';
}
cout << '\n';
}
}