#include <iostream>
#include <vector>
#include <assert.h>
class SegmentTree {
private:
int N;
std::vector<int> tree;
void build(int u, int l, int r, const std::vector<int> &V) {
if (l == r) {
tree[u] = V[l];
return;
}
int m = (l + r) / 2;
build(2 * u, l, m, V);
build(2 * u + 1, m + 1, r, V);
tree[u] = std::max(tree[2 * u], tree[2 * u + 1]);
}
void update(int u, int l, int r, int pos, int val) {
if (l == r) {
tree[u] = val;
return;
}
int m = (l + r) / 2;
if (pos <= m) {
update(2 * u, l, m, pos, val);
} else {
update(2 * u + 1, m + 1, r, pos, val);
}
tree[u] = std::max(tree[2 * u], tree[2 * u + 1]);
}
int query(int u, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tree[u];
}
int m = (l + r) / 2;
int lSide = 0, rSide = 0;
if (ql <= m) {
lSide = query(2 * u, l, m, ql, qr);
}
if (m < qr) {
rSide = query(2 * u + 1, m + 1, r, ql, qr);
}
return std::max(lSide, rSide);
}
public:
SegmentTree(const std::vector<int> &V) : N((int)V.size()), tree((int)V.size() * 4) {
build(1, 0, N - 1, V);
}
void update(int pos, int val) {
update(1, 0, N - 1, pos, val);
}
int query(int l, int r) {
return query(1, 0, N - 1, l, r);
}
};
int N, Q;
std::vector<int> V;
int main() {
assert(freopen("arbint.in", "r", stdin));
assert(freopen("arbint.out", "w", stdout));
std::cin >> N >> Q;
V.resize(N);
for (int &x : V) {
std::cin >> x;
}
SegmentTree DS(V);
for (int q = 0; q < Q; q++) {
int op, a, b;
std::cin >> op >> a >> b;
if (op == 0) {
std::cout << DS.query(a - 1, b - 1) << "\n";
} else {
DS.update(a - 1, b);
}
}
return 0;
}