/// problema ne cere sa determinam maximul din diverse invervale
/// si sa updatam unele valori din vector (Arbori de intervale infoarena)
#include<bits/stdc++.h>
using namespace std;
FILE *f=fopen("arbint.in","r");
FILE *g=fopen("arbint.out","w");
const int NMAX = 100004;
int N,Q;
int Tree[4*NMAX];/// aici salvam intervalele sub forma unui abore
void Build(int nod,int left,int right)
{
/// daca am ajuns la o frunza citim valoarea
if(left==right)
{fscanf(f,"%d",&Tree[nod]);return;}
int mid = left + (right-left)/2;
Build(nod*2,left,mid);
Build(nod*2+1,mid+1,right);
/// maximul intervalului este maximul dintre cele 2 subintervale
Tree[nod]=max(Tree[2*nod],Tree[2*nod+1]);
}
void Read()
{
fscanf(f,"%d%d",&N,&Q);
Build(1,1,N);
}
int Query(int nod,int left,int right,int x,int y)
{
/// daca intervalul [left,right] se afla in totalitate in [x,y]
if(x<=left&&right<=y)
return Tree[nod];
int max1=-1,max2=-1;
int mid = left + (right-left)/2;
/// daca intervalul [x,y] se intersecteaza cu [left,mid]
if(x<=mid)
max1 = Query(2*nod,left,mid,x,y);
if(y>=mid+1) /// daca intervalul [x,y] se intersecteaza cu [mid+1,right]
max2 = Query(2*nod+1,mid+1,right,x,y);
return max(max1,max2);
}
void Update(int nod,int left,int right,int pos,int val)
{
/// fiind in intervalul corect daca left==right
/// atunci am gasit elementul caruia trebuie sa ii modificam valoarea
if(left==right)
{Tree[nod]=val;return;}
int mid = left + (right-left)/2;
/// daca pozitia se afla in intervalul [left,mid]
if(pos<=mid)
Update(2*nod,left,mid,pos,val);
/// altfel daca pozitia se afla in intervalul [mid+1,right]
else Update(2*nod+1,mid+1,right,pos,val);
/// actualizam termenii inca odata avand in vedere ca valorile s-au schimbat
Tree[nod]=max(Tree[2*nod],Tree[2*nod+1]);
}
void Solve()
{
for(int q=1;q<=Q;q++)
{
int tip,x,y;
fscanf(f,"%d%d%d",&tip,&x,&y);
if(tip==0)
fprintf(g,"%d\n",Query(1,1,N,x,y));
else Update(1,1,N,x,y);
}
}
int main()
{
Read();
Solve();
fclose(f);
fclose(g);
return 0;
}