#include <fstream>
using namespace std;
const int N = 1 << 18;
const int INF = 1e9;
int t[N];
int interogare(int p, int st, int dr, int a, int b)
{
///returneaza max([st,dr] intersectat cu [a,b])
if (a <= st && dr <= b)///[st,dr] e inclus in [a,b]
{
return t[p];
}
int m = (st + dr) / 2, fs = 2*p, fd = 2*p + 1;
int rs = -INF, rd = -INF;
if (a <= m)///intervalul [a,b] intersecteaza jumatatea stanga
{
rs = interogare(fs, st, m, a, b);
}
if (b >= m + 1)///intervalul [a,b] intersecteaza jumatatea dreapta
{
rd = interogare(fd, m + 1, dr, a, b);
}
return max(rs, rd);
}
void actualizare(int p, int st, int dr, int poz, int val)
{
if (st == dr)///nodul curent este o frunza, rez retinut e chiar v[st]
{
t[p] = val;
return;
}
int m = (st + dr) / 2, fs = 2*p, fd = 2*p + 1;
if (poz <= m)///poz modificata e in prima jumatate
{
actualizare(fs, st, m, poz, val);
}
else
{
actualizare(fd, m + 1, dr, poz, val);
}
///actualizez rezultatul curent (t[p]) in functie de cele ale fiilor
t[p] = max(t[fs], t[fd]);
}
int main()
{
ifstream in("arbint.in");
ofstream out("arbint.out");
int m, n;
in >> n >> m;
for (int i = 1; i <= n; i++)
{
int aux;
in >> aux;
actualizare(1, 1, n, i, aux);
}
for (int i = 0; i < m; i++)
{
int tip;
in >> tip;
if (tip == 0)
{
int a, b;
in >> a >> b;
out << interogare(1, 1, n, a, b) << "\n";
}
else
{
int poz, val;
in >> poz >> val;
actualizare(1, 1, n, poz, val);
}
}
in.close();
out.close();
return 0;
}