#include <stdio.h>
#define MAXN 100005
int tree[4 * MAXN]; // vectorul pentru arbore
int A[MAXN]; // vectorul A din enunt
int max(int a, int b)
{
if (a>b) return a;
else return b;
}
// Reprezentarea arborelui de intervale in vectorul tree:
// radacina e pe pozitia 1
// la pozitia 2*i - copilul stang al nodului i
// la pozitia 2*i+1 - copilul drept al nodului i
void build(int nod, int stanga, int dreapta)
{
if (stanga == dreapta) // am ajuns la o frunza (1 singur element)
{
tree[nod] = A[stanga];
return;
}
int mijloc = (stanga + dreapta) / 2;
build(2 * nod, stanga, mijloc); // copilul stang
build(2 * nod + 1, mijloc + 1, dreapta); // copilul drept
// maximul de pe nodul curent = maximul dintre cei doi copii
tree[nod] = max(tree[2 * nod], tree[2 * nod + 1]);
}
// Operatia de tip 1
void update(int nod, int stanga, int dreapta, int pozitie, int valoare_noua)
{
if (stanga == dreapta) // am gasit elementul pe care vrem sa il modificam
{
tree[nod] = valoare_noua;
return;
}
int mijloc = (stanga + dreapta) / 2;
if (pozitie <= mijloc) // pozitia e in prima jumatate, mergem in copilul stang
update(2 * nod, stanga, mijloc, pozitie, valoare_noua);
else // pozitia e in a doua jumatate, mergem in copilul drept
update(2 * nod + 1, mijloc + 1, dreapta, pozitie, valoare_noua);
tree[nod] = max(tree[2 * nod], tree[2 * nod + 1]); // modificam arborele
}
// Operatia de tip 0
int find_max(int nod, int stanga, int dreapta, int a, int b)
{
if (a <= stanga && b >= dreapta) // intervalul nodului e complet inclus in intervalul cerut => returnam valoarea
return tree[nod];
int mijloc = (stanga + dreapta) / 2;
int maxim_gasit = -1;
if (a <= mijloc) // intervalul cerut are o parte in stanga => cautam acolo
maxim_gasit = max(maxim_gasit, find_max(2 * nod, stanga, mijloc, a, b));
if (b > mijloc) // intervalul cerut are o parte in dreapta => cautam acolo
maxim_gasit = max(maxim_gasit, find_max(2 * nod + 1, mijloc + 1, dreapta, a, b));
return maxim_gasit;
}
int main(void)
{
FILE *fin = fopen("arbint.in", "r");
FILE *fout = fopen("arbint.out", "w");
if (fin == NULL || fout == NULL) return 1;
int N, M;
fscanf(fin, "%d %d", &N, &M);
for (int i = 1; i <= N; i++)
{
fscanf(fin, "%d", &A[i]);
}
build(1, 1, N); // construim arborele
for (int i = 0; i < M; i++)
{
int operatie, a, b;
fscanf(fin, "%d %d %d", &operatie, &a, &b);
if (operatie == 0)
fprintf(fout, "%d\n", find_max(1, 1, N, a, b));
if (operatie == 1)
update(1, 1, N, a, b);
}
fclose(fin);
fclose(fout);
return 0;
}