#include <fstream>
#include <iostream>
using namespace std;
ifstream f("arbint.in");
ofstream g("arbint.out");
int n, m, x, opt, pos, p, u, macs;
int arb[500001];
void update(int nod, int p, int u, int pos, int val) {
int mij;
if (p == u) { //daca intervalul [p, u] are un singur element => frunza
arb[nod] = val;
}
else { //altfel trebuie sa coboram in arbore
mij = (p + u) / 2;
if (pos <= mij) //daca pozitia pe care trebuie inserat este inclusa in intervalul subarborelui stang
update(2 * nod, p, mij, pos, val);
else update(2 * nod + 1, mij + 1, u, pos, val);
if (arb[2 * nod] > arb[2 * nod + 1]) //se updateaza valoarea intervalului curent cu maximul dintre maximele fiilor
arb[nod] = arb[2 * nod];
else arb[nod] = arb[2 * nod + 1];
}
}
void query(int nod, int p, int u, int ip, int iu) {
int mij;
if (ip <=p && u <= iu) { //daca intervalul curent este inauntrul intervalului cerut
if (macs < arb[nod])
macs = arb[nod];
}
else { //daca nu, continuam sa cautam
mij = (p + u) / 2;
if (ip <= mij) //daca inceputul intervalului cerut este mai mic decat mijlocul intervalului curent, adica daca exista elemente din intervalul cerut in subarborele stang
query(2 * nod, p, mij, ip, iu);
if (mij < iu) //daca sfarsitul intervalului cerut este mai mare decat mijlocul intervalului curent, ...
query(2 * nod + 1, mij + 1, u, ip, iu);
}
}
int main()
{
f >> n >> m;
for (int i = 1; i <= n; i++) {
f >> x;
update(1, 1, n, i, x);
}
for (int i = 0; i < m; i++) {
f >> opt;
if (opt) { //se modifica elementul de pe pozitia ceruta in arborele de intervale
f >> pos >> x;
update(1, 1, n, pos, x);
}
else { //se cauta maximul din intervalul cerut
f >> p >> u;
macs = 0;
query(1, 1, n, p, u);
g << macs << "\n";
}
}
return 0;
}