#include <stdio.h>
#define Nadejde 131072
/** Implementarea arborilor de intervale:
* (1)
[1, 5]
(2) / \ (3)
[1, 3] [4, 5]
(4)/ \ (5) (6) / \ (7)
[1, 2] [3, 3] [4, 4] [5, 5]
(8) / \ (9)
[1, 1] [2, 2]
* Precizari:
* * Fiecare nod "u" are 2 fii: nodul 2u, respectiv 2u + 1.
**************************************************************************
* Functia update: Trebuie sa modificam pozitia "pos" in valoarea "val":
* Exemplu: pos = 2, val = 3.
* Vom pleca din radacina, reprezentata de nodul 1 -> [1, 5].
* In acest moment, ne intereseaza care dintre fii ei contine pozitia 2.
* Observam ca fiul stang [1, 3] contine pozitia 2, deci vom avansa pe partea stanga prin nodul 2.
* Am ajuns in nodul 2. Cautam, analog, care dintre fii sai contine pozitia 2 (fiul stang - nodul 4).
* In nodul 4 -> [1, 2], mergem catre intervalul de lungime 1, [2, 2] continut de nodul 9.
* Resetam valoarea continuta de acest nod.
* Pentru a reconstitui arborele de intervale, va trebui sa ne intoarcem pe unde am venit, reinitializand
* maximul din fiecare nod.
* Drumul nostru a fost: 1, 2, 4.
* Pentru fiecare astfel de nod, ne vom uita la fiul stang si la fiul drept pentru a vedea daca s-a imbunatatit
* maximul curent.
***************************************************************************
***************************************************************************
* Functia query: Ne intereseaza maximul din intervalul [a, b].
* Exemplu: a = 2, b = 4.
* Vom pleca, exact ca la Update, din radacina.
* In momentul in care suntem intr-un nod "u" urmarim 3 lucruri:
* I) Daca intervalul reprezentat este inclus in [a, b],
* -> Reactualizam raspunsul.
* II) Daca intervalul reprezentat de fiul stang se intersecteaza cu [a, b],
* -> Vom intra in fiul stang, cautand actualizari ale raspunsului.
* III) Daca intervalul reprezentat de fiul drept se intersecteaza cu [a, b],
* -> Vom intra in fiul drept, cautand actualizari ale raspunsului.
***************************************************************************
* Multumim Doamne!
**/
int N, M;
int tree[2 * Nadejde];
int max;
/** max(X, Y). **/
int MAX(int X, int Y) {
return X > Y ? X : Y;
}
/** Updateaza arborele in nodul "node" -> [left, right], pentru pozitia "pos" si valoarea "val". **/
void update(int node, int left, int right, int pos, int val) {
if (left == right) {
tree[node] = val;
return;
}
int mid = (left + right) >> 1;
if (pos <= mid) {
update(2 * node, left, mid, pos, val);
} else {
update(2 * node + 1, mid + 1, right, pos, val);
}
tree[node] = MAX(tree[2 * node], tree[2 * node + 1]);
}
/** Obtine o informatie din nodul "node" -> [left, right], pentru intervalul [a, b]. **/
void query(int node, int left, int right, int a, int b) {
if ((a <= left) && (right <= b)) {
max = MAX(max, tree[node]);
return;
}
int mid = (left + right) >> 1;
if (a <= mid) {
query(2 * node, left, mid, a, b);
}
if (b > mid) {
query(2 * node + 1, mid + 1, right, a, b);
}
}
int main(void) {
int i, val, task, a, b;
FILE *f = fopen("arbint.in", "r");
/* Citirea datelor si construirea arborelui. */
fscanf(f, "%d %d", &N, &M);
for (i = 1; i <= N; i++) {
fscanf(f, "%d", &val);
update(1, 1, N, i, val);
}
/* Citirea intrebarilor si afisarea raspunsurilor. */
freopen("arbint.out", "w", stdout);
while (M) {
fscanf(f, "%d %d %d", &task, &a, &b);
if (task == 0) {
max = 0;
query(1, 1, N, a, b);
fprintf(stdout, "%d\n", max);
} else {
update(1, 1, N, a, b);
}
M--;
}
fclose(f);
fclose(stdout);
/// Multumim Doamne!
puts("Doamne ajuta!");
return 0;
}