// https://infoarena.ro/problema/arbint
#include <iostream>
#include <fstream>
#include <assert.h>
#include <algorithm>
#include <vector>
using namespace std;
unsigned int* tree;
// Functia construieste arborele de intervale
void Build(unsigned int node, unsigned int start, unsigned int end, const vector<unsigned int>& A) {
if (start == end) {
// Frunza: stocheaza valoarea elementului original
tree[node] = A[start];
}
else {
unsigned int mid = (start + end) / 2;
Build(2 * node, start, mid, A); // Construieste subarborele stang
Build(2 * node + 1, mid + 1, end, A); // Construieste subarborele drept
tree[node] = max(tree[2 * node], tree[2 * node + 1]); // Combina rezultatele
}
}
// Functia actualizeaza valoarea unui element in arborele de intervale
void Update(unsigned int node, unsigned int start, unsigned int end, unsigned int idx, unsigned int value) {
if (start == end) {
// Am ajuns la frunza
tree[node] = value;
}
else {
unsigned int mid = (start + end) / 2;
if (idx <= mid) {
// Actualizam subarborele stang
Update(2 * node, start, mid, idx, value);
}
else {
// Actualizam subarborele drept
Update(2 * node + 1, mid + 1, end, idx, value);
}
// Recalculam valoarea maxima pentru nodul curent
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
}
// Functia interogheaza arborele de intervale pentru a gasi maximul in intervalul [l, r]
unsigned int Query(unsigned int node, unsigned int start, unsigned int end, unsigned int l, unsigned int r) {
// Intervalul curent nu se intersecteaza cu [l, r]
if (r < start || end < l) {
return 0; // Returneaza o valoare care nu va afecta maximul
}
// Intervalul curent este inclus in [l, r]
if (l <= start && end <= r) {
return tree[node];
}
// Intervalul se intersecteaza partial, interogam subarborii
unsigned int mid = (start + end) / 2;
unsigned int p1 = Query(2 * node, start, mid, l, r);
unsigned int p2 = Query(2 * node + 1, mid + 1, end, l, r);
return max(p1, p2);
}
int main() {
ifstream fin("arbint.in");
ofstream fout("arbint.out");
if (!fin.is_open() || !fout.is_open()) {
cerr << "Eroare la deschiderea fisierelor!" << endl;
return 1;
}
unsigned int M, N;
fin >> N >> M;
tree = new unsigned int[4 * N + 1]; // Alocam memorie pentru arborele de intervale
vector<unsigned int> A(N + 1); // Vector pentru a stoca valorile initiale
for (unsigned int i = 1; i <= N; ++i) {
fin >> A[i];
}
// Construim arborele de intervale cu valorile initiale
Build(1, 1, N, A);
for (unsigned int i = 0; i < M; ++i) {
unsigned int op, a, b;
fin >> op >> a >> b;
if (op == 0) {
// Interogare pentru maxim
fout << Query(1, 1, N, a, b) << endl;
}
else {
// Actualizare a valorii
Update(1, 1, N, a, b);
}
}
// Eliberam memoria alocata pentru arborele de intervale
delete[] tree;
tree = nullptr;
fin.close();
fout.close();
return 0;
}