#include <fstream>
#include <math.h>
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
const int MAXN = 1e5;
const int MAXSQN = 317;
int max(int a, int b) {
return a > b ? a : b;
}
struct SqrtDecomp {
int n;
int sq;
int *a;
int chunks[MAXSQN] = {};
void init(int _n, int _a[MAXN]) {
n = _n;
a = _a;
sq = sqrt(n);
// printf("init cu n = %d; sqrt %d\n", n, sq);
for (int i = 0; i < n; ++i) {
// printf(" %d (%d) e in chunk %d\n", i, a[i], i / sq);
if (a[i] > chunks[i / sq]) {
chunks[i / sq] = a[i];
}
}
}
int max_query(int l, int r) {
int l_chunk = (l + sq - 1) / sq,
r_chunk = (r - 1) / sq;
int ans = -1;
int i;
// printf("query(%d -> %d); chunks %d -> %d; L incepe la %d, R se termina la %d\n", l, r, l_chunk, r_chunk, l_chunk * sq, (r_chunk + 1) * sq - 1);
for (l; l < l_chunk * sq; ++l) {
ans = max(ans, a[l]);
// printf("l = %d; ans %d\n", l, ans);
}
for (i = l_chunk; i <= r_chunk; ++i) {
ans = max(ans, chunks[i]);
// printf("ch = %d; ans %d\n", i, ans);
}
for (r; r >= (r_chunk + 1) * sq - 1; --r) {
ans = max(ans, a[r]);
// printf("r = %d; ans %d\n", r, ans);
}
return ans;
}
void set_val(int pos, int val) {
int ch = pos / sq;
// printf("update pos %d = %d\n", pos, val);
if (chunks[ch] == a[pos]) {
// printf(" trebuie sa resetez max (merg de la %d -> %d)\n", ch * sq, min(n, (ch + 1) * sq - 1));
a[pos] = val;
chunks[ch] = -1;
for (int i = ch * sq; i < min(n, (ch + 1) * sq); ++i) {
// printf(" a[%d] = %d\n", i, a[i]);
chunks[ch] = max(chunks[ch], a[i]);
}
// printf(" => = %d\n", chunks[ch]);
} else {
a[pos] = val;
}
}
} batog;
int a[MAXN];
int n, m;
void citire() {
fin >> n >> m;
for (int i = 0; i < n; ++i) {
fin >> a[i];
}
}
void process_queries() {
int qt, a, b;
for (int i = 0; i < m; ++i) {
fin >> qt >> a >> b;
if (qt == 0) {
fout << batog.max_query(a - 1, b - 1) << '\n';
} else {
batog.set_val(a - 1, b);
}
}
}
int main() {
citire();
batog.init(n, a);
process_queries();
}