#include <iostream>
using namespace std;
const int NMAX = 1e5 + 5;
const char nl = '\n';
int vec[NMAX];
class SegmentTree {
private:
int tree[4 * NMAX], v[NMAX];
int n;
void build(int node = 1, int l = 1, int r = -1) {
if (r == -1) {
r = n;
}
if (l > r) {
return;
}
if (l == r) {
tree[node] = v[l];
return;
}
int mid = l + (r - l) / 2;
build(2 * node, l, mid);
build(2 * node + 1, mid + 1, r);
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
int query(int ql, int qr, int node = 1, int l = 1, int r = -1) const {
if (r == -1) {
r = n;
}
if (l > r || r < ql || l > qr) {
return 0;
}
if (l >= ql && r <= qr) {
return tree[node];
}
int mid = l + (r - l) / 2;
return max(query(ql, qr, 2 * node, l, mid),
query(ql, qr, 2 * node + 1, mid + 1, r));
}
void update(int pos, int value, int node = 1, int l = 1, int r = -1) {
if (r == -1) {
r = n;
}
if (l == r) {
tree[node] = value;
return;
}
int mid = l + (r - l) / 2;
if (pos <= mid) {
update(pos, value, 2 * node, l, mid);
} else {
update(pos, value, 2 * node + 1, mid + 1, r);
}
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
public:
SegmentTree(int size) : n(size) {}
void set_values(const int arr[]) {
for (int i = 1; i <= n; ++i) {
v[i] = arr[i - 1];
}
build();
}
int query_range(int l, int r) {
return query(l, r);
}
void update_value(int pos, int value) {
update(pos, value);
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
freopen("arbint.int", "r", stdin);
freopen("arbint.out", "w", stdout);
int n, q;
cin >> n >> q;
for (int i = 0; i < n; ++i) {
cin >> vec[i];
}
SegmentTree tree(n);
tree.set_values(vec);
while (q--) {
int op, x, y;
cin >> op >> x >> y;
if (op == 0) {
cout << tree.query_range(x, y) << nl;
} else {
tree.update_value(x, y);
}
}
cout << nl;
return 0;
}