#include <fstream>
#include <vector>
using namespace std;
ifstream fin("arbint.in");
ofstream fout("arbint.out");
int rez;
struct tip_arbore
{
vector <int> arbore;
int tsize, intersize, rez;
void init(int n)
{
tsize = 1;
while(tsize < n)
tsize <<= 1;
intersize = tsize;
tsize <<= 1;
arbore.resize(tsize);
}
void build(vector <int> a, int node, int lx, int rx)
{
if(rx - lx == 1)
{
if(lx < a.size())
arbore[node] = a[lx];
return;
}
int mij = (lx + rx) / 2;
build(a, 2 * node + 1, lx, mij);
build(a, 2 * node + 2, mij, rx);
arbore[node] = max(arbore[2 * node + 1], arbore[2 * node + 2]);
}
void build(vector <int> a)
{
build(a, 0, 0, intersize);
}
void setare(int i, int v, int node, int lx, int rx)
{
if(rx - lx == 1)
{
arbore[node] = v;
return;
}
int mij = (lx + rx) / 2;
if(i < mij)
setare(i, v, 2 * node + 1, lx, mij);
else
setare(i, v, 2 * node + 2, mij, rx);
arbore[node] = max(arbore[2 * node + 1], arbore[2 * node + 2]);
}
void setare(int i, int v)
{
setare(i, v, 0, 0, intersize);
}
int get_max(int l, int r, int node, int lx, int rx)
{
if(rx <= l || lx >= r)
return 0;
if(lx >= l && rx <= r)
return arbore[node];
int mij =(lx + rx) / 2, rez1, rez2;
if(mij >= lx)
rez1 = get_max(l, r, 2 * node + 1, lx, mij);
if(mij <= rx)
rez2 = get_max(l, r, 2 * node + 2, mij, rx);
return max(rez1, rez2);
}
int get_max(int l, int r)
{
return get_max(l, r, 0, 0, intersize);
}
};
int main()
{
int n, q, i;
fin >> n >> q;
vector <int> a(n);
tip_arbore stree;
stree.init(n);
for(i = 0; i < n; i++)
fin >> a[i];
stree.build(a);
for(i = 0; i < q; i++)
{
int tip, a, b;
fin >> tip >> a >> b;
if(tip == 0)
--a, --b;
else
--a;
if(tip == 1)
stree.setare(a, b);
else
rez = 0, fout << stree.get_max(a, b + 1) << '\n';
}
return 0;
}