#include <fstream>
#include <set>
#include <queue>
#include <iostream>
#include <cstring>
using namespace::std;
int n, m;
int v[1000005];
class SegmentTree {
private:
int *tree;
int n;
int query(int l, int r, int i, int a, int b) {
// cout << a << ' ' << b << ' ' << i << '\n';
// completely inside the segment
if (l <= a && b <= r) return tree[i];
// completely outside the segment
if (l >= b || r <= a) return -999999999;
int mid = (a + b) / 2;
int left = query(l, r, i * 2, a, mid);
int right = query(l, r, i * 2 + 1, mid, b);
return max(left, right);
}
void update(int pos, int val, int i, int a, int b) {
// completely outside the segment
if (pos >= b || pos < a) return;
if (a == b - 1) {
tree[i] = val;
return;
}
int mid = (a + b) / 2;
update(pos, val, i * 2, a, mid);
update(pos, val, i * 2 + 1, mid, b);
tree[i] = max(tree[i * 2], tree[i * 2 + 1]);
}
public:
SegmentTree(int n, int v[]) {
this->n = n;
tree = new int[4 * n];
memset(tree, 0, 4 * n);
for (int i = 0; i < n; i++) {
assign(i, v[i]);
}
}
~SegmentTree() {
delete[] tree;
}
int getMax(int l, int r) {
return query(l, r, 1, 0, n);
}
void assign(int pos, int val) {
update(pos, val, 1, 0, n);
}
};
int main() {
ifstream fin("arbint.in");
ofstream fout("arbint.out");
fin >> n >> m;
for (int i = 0; i < n; i++) fin >> v[i];
SegmentTree *st = new SegmentTree(n, v);
while (m--) {
int c, a, b;
fin >> c >> a >> b;
a--;
if (c == 0) {
fout << st->getMax(a, b) << '\n';
} else {
st->assign(a, b);
}
}
delete st;
}