#include <bits/stdc++.h>
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
#define ll long long
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define pll pair<ll, ll>
#define all(x) (x).begin(), (x).end()
#define fi first
#define se second
template<typename Int>
class SegmentTree {
public:
SegmentTree() {}
SegmentTree(int n) {
this->n = n;
seg.resize(4 * n + 5);
}
template<typename Array>
SegmentTree(int n, Array& v) {
this->n = n;
seg.resize(4 * n + 5);
build(1, 1, n, v);
}
void update(int poz, Int& val) {
return update(1, 1, n, poz, val);
}
Int query(int left, int right) {
return query(1, 1, n, left, right);
}
private:
vector<Int> seg;
int n;
Int func(Int x, Int y) {
return max(x, y);
}
template<typename Array>
void build(int node, int l, int r, Array& v) {
if (l == r) {
seg[node] = v[l];
return;
}
int m = (l + r) / 2;
int ls = 2 * node;
int rs = 2 * node + 1;
build(ls, l, m, v);
build(rs, m + 1, r, v);
seg[node] = func(seg[ls], seg[rs]);
}
void update(int node, int l, int r, int poz, Int& val) {
if (l == r) {
seg[node] = val;
return;
}
int m = (l + r) / 2;
int ls = 2 * node;
int rs = 2 * node + 1;
if (poz <= m) update(ls, l, m, poz, val);
else update(rs, m + 1, r, poz, val);
seg[node] = max(seg[ls], seg[rs]);
}
Int query(int node, int l, int r, int a, int b) {
if (l >= a && r <= b) {
return seg[node];
}
int m = (l + r) / 2;
int ls = 2 * node;
int rs = 2 * node + 1;
int x = 0;
int y = 0;
if (a <= m)
x = query(ls, l, m, a, b);
if (b > m)
y = query(rs, m + 1, r, a, b);
return func(x, y);
}
};
const int nmax = 100005;
vector<int> v;
SegmentTree<int> myTree;
int main() {
int n, q;
fin >> n >> q;
v.resize(n + 5);
for (int i = 1; i <= n; i++)
fin >> v[i];
myTree = SegmentTree<int>(n, v);
for (; q; q--) {
int op;
fin >> op;
if (op == 1) {
int poz, val;
fin >> poz >> val;
myTree.update(poz, val);
} else {
int left, right;
fin >> left >> right;
fout << myTree.query(left, right) << '\n';
}
}
return 0;
}