#include <fstream>
#include <fstream>
#define MOD 666013
using namespace std;
ifstream f ("arbint.in");
ofstream g ("arbint.out");
/// arbori de intervale
/// se face un vector unde copii ai indicele 2i si 2i+1, i fiind indicele parintelui
/// cand se cauta prop unui interval anume consideram numai intervalele incluse in intervalul dat
/// daca un interval contine info de valoare atunci coboram pe el
int v[500009] ;
void update(int st, int dr, int f, int poz, int a)
{
/// st si dreapta este rangeul in care updatam
/// a este valoarea vare o bagam
int mij = (st + dr) / 2 ;
///cout << st << " " << dr << endl ;
if(st == dr)
{
v[poz] = a ;
return ;
}
if(f > mij)
{
update(mij + 1, dr, f, poz * 2 + 1, a) ;
v[poz] = max(v[poz * 2], v[poz * 2 + 1]) ;
}
else
{
update(st, mij, f, poz * 2, a) ;
v[poz] = max(v[poz * 2], v[poz * 2 + 1]) ;
}
}
int query(int st, int dr, int poz, int ST, int DR)
{
/// daca intervalul curent este complet inauntrul celui cautat returnam val lui
/// alftel returnam valoarea din el
/// daca intervalul e off rau ii dam return 0 ;
if(DR < st || ST > dr)return 0 ;
if(ST >= st && DR <= dr)return v[poz] ;
return max(query(st, dr, poz * 2, ST, (ST + DR) / 2), query(st, dr, poz * 2 + 1, (ST + DR) / 2 + 1, DR)) ;
}
int main()
{
int n, q ;
cin >> n >> q ;
for(int f = 1, a ; f <= n ; f ++)
{
cin >> a ;
update(1, n, f, 1, a) ;
}
while(q --)
{
int cer, a, b ;
cin >> cer >> a >> b ;
if(!cer)cout << query(a, b, 1, 1, n) << '\n' ;
else update(1, n, a, 1, b) ;
}
return 0;
}
/// 3 5 6 2