#include <iostream>
#include <vector>
#define aintData int
#define aintNull 0
using namespace std;
// #DEFINE aintNull
// #DEFINE aintData
struct AINT {
int offset;
// int n;
vector<aintData> aint;
aintData merge (aintData a, aintData b)
{
aintData par;
par = max(a, b);
return par;
}
void build (int nod, int l, int r, vector<aintData>& a)
{
if (l == r){
aint[nod] = a[l];
return;
}
int m = (l + r) / 2;
build(2 * nod, l, m, a);
build(2 * nod + 1, m + 1, r, a);
aint[nod] = merge(aint[2 * nod], aint[2 * nod + 1]);
}
AINT(int _offset, vector<aintData>& a)
{
offset = _offset;
aint.resize(2 * offset);
build(1, 1, offset, a);
}
void upd (int nod, int l, int r, int pos, int val)
{
if (l == r)
{
if (l == pos) {
aint[nod] = val;
}
return;
}
if (l > pos || r < pos) return;
int m = (l + r) / 2;
upd(2 * nod, l, m, pos, val);
upd(2 * nod + 1, m + 1, r, pos, val);
aint[nod] = merge(aint[2 * nod], aint[2 * nod + 1]);
}
void update (int pos, int val)
{
upd(1, 1, offset, pos, val);
}
aintData qry (int nod, int l, int r, int ql, int qr)
{
if (l >= ql && r <= qr)
{
return aint[nod];
}
if (r < ql || l > qr) return aintNull;
int m = (l + r) / 2;
return merge(qry(2 * nod, l, m, ql, qr),
qry(2 * nod + 1, m + 1, r, ql, qr));
}
aintData query(int l, int r)
{
return qry(1, 1, offset, l, r);
}
};
int main ()
{
freopen("arbint.in", "r", stdin);
freopen("arbint.out", "w", stdout);
int n, m; cin >> n >> m;
vector<int> a;
a.push_back(0);
for (int i = 1; i <= n; i++)
{
int x; cin >> x;
a.push_back(x);
}
AINT aint(n, a);
while (m--)
{
int q; cin >> q;
if (q == 0)
{
int l, r; cin >> l >> r;
cout << aint.query(l, r) << '\n';
}
else {
int pos, val; cin >> pos >> val;
aint.update(pos, val);
}
}
}