//#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <algorithm>
#include <cassert>
#include <queue>
using namespace std;
ifstream cin("arbint.in");
ofstream cout("arbint.out");
int arb[400005], v[100005], tip, a, b;
int n, q, x;
void build(int nod = 1, int st = 1, int dr = n) {
if(st == dr) {
arb[nod] = v[st];
return;
}
int mij = (st + dr) / 2;
build(2 * nod, st, mij);
build(2 * nod + 1, mij + 1, dr);
arb[nod] = max(arb[2 * nod], arb[2 * nod + 1]);
}
void update(int pos, int val, int nod = 1, int st = 1, int dr = n) {
if(st == dr) {
arb[nod] = val;
return;
}
int mij = (st + dr) / 2;
if(pos <= mij) { // continuam in fiul din stanga [st, mij]
update(pos, val, 2 * nod, st, mij);
} else { // continuam in fiul din dreapta [mij+1, dr]
update(pos, val, 2 * nod + 1, mij + 1, dr);
}
arb[nod] = max(arb[2 * nod], arb[2 * nod + 1]);
}
int query(int a, int b, int nod = 1, int st = 1, int dr = n) {
if(st >= a && dr <= b) { // intervalul [st, dr] e inclus in [a, b]
return arb[nod];
}
int maxim = 0;
int mij = (st + dr) / 2;
// st a mij b dr
if(a <= mij) { // mergem in fiul din stanga
int val = query(a, b, 2 * nod, st, mij);
if(val > maxim)
maxim = val;
}
if(b >= mij+1) { // mergem in fiul din dreapta
int val = query(a, b, 2 * nod + 1, mij + 1, dr);
if(val > maxim)
maxim = val;
}
return maxim;
}
int main() {
cin >> n >> q;
for(int i = 1; i <= n; i ++) {
cin >> v[i];
} // n log n
build();
for(int i = 1; i <= q; i ++) {
cin >> tip >> a >> b;
if(tip == 0)
cout << query(a, b) << '\n';
else
update(a, b);
}
return 0;
}