#include <fstream>
using namespace std;
ifstream in ("arbint.in");
ofstream out ("arbint.out");
const int N = 1 << 18;
const int INF = 1e9;
int t[N];
///returneaza maximul pe intersectia dintre [st, dr] si [a, b]
int interogare(int p, int st, int dr, int a, int b) {
///[st, dr] inclus in [a,b]
if(a <= st && dr <= b) {
return t[p];
}
int m = (st + dr) / 2;
int fs = 2 * p;
int fd = 2 * p + 1;
int rs = -INF, rd = -INF;
///intervalul [a, b] interseceteaza jumatatea stanga
if(a <= m) {
rs = interogare(fs, st, m, a, b);
}
///inervalul [a, b] intersecteaza jumatatea dreapta
if(b > m) {
rd = interogare(fd, m + 1, dr, a, b);
}
return max(rs, rd);
}
void actualizare(int p, int st, int dr, int poz, int val) {
///nodul curent este o frunza
if(st == dr) {
t[p] = val;
return;
}
int m = (st + dr) / 2;
int fs = 2 * p;
int fd = 2 * p + 1;
///pozitia modificata e in prima jumatate
if(poz <= m) {
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() {
int n, m, a, b;
bool cerinta;
in >> n >> m;
for(int i = 1; i <= n; i++) {
int x;
in >> x;
actualizare(1, 1, n, i, x);
}
for(int i = 0; i < m; i++) {
in >> cerinta >> a >> b;
if(cerinta == 0) {
out << interogare(1, 1, n, a, b) << "\n";
} else {
actualizare(1, 1, n, a, b);
}
}
return 0;
}