/* Arbori de inervale
*
* Consideram radacina nod avand asociat intervalul [st, dr];
*
* Daca st < dr atunci vom avea asociat subarborele stang T(st, mij), respectiv
* subarborele drept T(mij + 1, dr), unde mij este mijlocul intervalului [st, dr];
*
* Fiecare nod contine valoarea maxima din intervalul [st, dr] din vectorulA;
*
* Este folosit un HEAP pentru a stoca in memorie.
*/
#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>
std::ifstream fin("./doc/arbint.in");
std::ofstream fout("./doc/arbint.out");
struct Node {
int minimum, maximum;
long long valMax;
};
int n, m;
std::vector<int> intervallTree;
std::vector<long long> vectorA;
// Preluarea valorii maxime dintr-un nod
int interogate(int poz, int minimum, int maximum, int intervalA,
int intervalB) {
if (intervalA <= minimum && maximum <= intervalB) {
// Verificam daca am ajuns in intervalul corect (nodul)
return intervallTree[poz];
} else {
// Daca nu coboram mai mult in arbore
int leftVal = 0, rightVal = 0;
int middle = (minimum + maximum) / 2;
// Trecem pe nodul din stanga
if (intervalA <= middle) {
leftVal = interogate(2 * poz, minimum, middle, intervalA, intervalB);
}
// Trecem pe nodul din dreapta
if (intervalB > middle) {
rightVal =
interogate(2 * poz + 1, middle + 1, maximum, intervalA, intervalB);
}
return std::max(leftVal, rightVal);
}
}
// Actualizam valorile din arbore folosind un heap
void update(int a, int poz, int minimum, int maximum, int intervalA,
int intervalB) {
if (intervalA <= minimum && maximum <= intervalB) {
// Verificam daca am ajuns la nodurile frunza
intervallTree[poz] = a;
} else {
// Daca nu calculam urmatoarea pozitie dupa care ar trebui sa mergem in heap
int middle = (minimum + maximum) / 2;
// Trecem pe nodul din stanga
if (intervalA <= middle) {
update(a, 2 * poz, minimum, middle, intervalA, intervalB);
}
// Trecem pe nodul din dreapta
if (intervalB > middle) {
update(a, 2 * poz + 1, middle + 1, maximum, intervalA, intervalB);
}
// La intoarcerea recursiva actualizam toate nodurile parcurse in cazul in
// care valoare maxima se schimba
intervallTree[poz] =
std::max(intervallTree[2 * poz], intervallTree[2 * poz + 1]);
}
}
int main(int argc, char *argv[]) {
// Verificam daca fisierul se poate deschide
if (!fin.is_open()) {
std::cout << "ERROR: File failed to open!";
}
// Citirea vectorului
fin >> n >> m;
vectorA.resize(n + 1);
for (int i = 1; i <= n; i++) {
int x;
fin >> x;
vectorA[i] = x;
}
// Creem arborele de intervale
intervallTree.resize(2 * n);
for (int i = 1; i <= n; i++) {
update(vectorA[i], 1, 1, n, i, i);
}
// Citirea operatilor
for (int i = 0; i < m; i++) {
int op, a, b;
fin >> op >> a >> b;
if (op == 0) {
fout << interogate(1, 1, n, a, b) << '\n';
} else if (op == 1) {
update(b, 1, 1, n, a, a);
}
}
fin.close();
fout.close();
return 0;
}