#include <bits/stdc++.h>
using namespace std;
ifstream in("arbint.in");
ofstream out("arbint.out");
const int N=1e5+5;
int v[N],t[4*N];
void Build(int nod,int st,int dr)
{
if(st == dr)
{
t[nod]=v[st];
//in acest caz avem intervalul elementar (o pozitie), asa ca
//arborele va avea in pozitia nod valoarea elementului de pe acea pozitie
return;
}
int mij=(st+dr)/2;
//Construim recursiv arborele
Build(2*nod,st,mij);
Build(2*nod+1,mij+1,dr);
t[nod]=max(t[2*nod],t[2*nod+1]);
//arborele va avea in pozitia nod cea mai mare valoare dintre valoarea fiilor sai
//adica cea mai mare valoare din intervalul st-dr
}
void Update(int nod, int st,int dr,int poz,int val)
{
if(st == dr)
{
//intervalul elementar in cazul acesta este chiar pozitia poz
t[nod]=val;
return;
}
int mij=(st+dr)/2;
//Cautam binar pozitia si updatam recursiv subarborele unde se afla
//pozitia respectiva
if(mij>=poz) Update(2*nod,st,mij,poz,val);
if(mij<poz) Update(2*nod+1,mij+1,dr,poz,val);
t[nod]=max(t[2*nod],t[2*nod+1]);
//updatam restul arborelui daca este cazul dupa ce am schimbat valoarea
}
int query(int nod,int st,int dr,int x,int y)
{
if(x<=st && dr<=y) return t[nod];
int rez=0;
int mij=(st+dr)/2;
if(mij>=x) rez=max(rez,query(2*nod,st,mij,x,y));
if(mij<y) rez=max(rez,query(2*nod+1,mij+1,dr,x,y));
return rez;
}
int main()
{
int n,nrIntrebari;
in>>n>>nrIntrebari;
for(int i=1;i<=n;i++)
in>>v[i];
Build(1,1,n);
for(int i=1;i<=nrIntrebari;i++)
{
int cod,a,b;
in>>cod>>a>>b;
if(!cod) out<<query(1,1,n,a,b)<<'\n';
else Update(1,1,n,a,b);
}
return 0;
}