#include<stdio.h>
#define infile "arbint.in"
#define outfile "arbint.out"
#define nmax (2*(100*1000+1))
int x[nmax]; //valoarea maxima din acest subarbore
char y[nmax]; //daca intervalul ce este retinut de aceasta radacina a fost modificat in totalitate
int n; //numarul de elemente ale sirului
int m; //numarul de operatii
inline int max(int a, int b)
{
if(a>b) return a; return b;
}
void update(int nod, int st, int dr, int a, int b, int val)
{
if(y[nod/2]) { x[nod]=x[nod/2]; y[nod]=1; } //daca tatal nodului a fost modificat complet
if(a<=st && dr<=b) { x[nod]=val; y[nod]=1; return; } //modificam intervalul
int mij=(st+dr)/2; //mijlocul intervalului
if(a<=mij && 2*nod<nmax) update(2*nod,st,mij,a,b,val); //modificam partea stanga
if(mij<b && 2*nod+1<nmax) update(2*nod+1,mij+1,dr,a,b,val); //modificam partea dreapta
if(2*nod<nmax) x[nod]=x[2*nod]; //valoarea maxima din partea stanga
if(2*nod+1<nmax) x[nod]=max(x[nod],x[2*nod+1]); //valoarea maxima din partea dreapta
y[nod]=0; //marcam ca acest nod nu a fost modificat in totalitate
}
int query(int nod, int st, int dr, int a, int b)
{
if(a<=st && dr<=b) return x[nod]; //daca intervalul este complet, am gasit valoarea
int mij=(st+dr)/2; //mijlocul intervalului
int val=0; //valoarea maxima din acest arbore
if(a<=mij && 2*nod<nmax) val=query(2*nod,st,mij,a,b); //valoarea maxima din arborele stang
if(mij<b && 2*nod+1<nmax) val=max(val,query(2*nod+1,mij+1,dr,a,b)); //vedem daca in intervalul drept avem o valoare mai mare
return val; //returnam valoarea
}
int main()
{
int i,j,a,b;
freopen(infile,"r",stdin);
freopen(outfile,"w",stdout);
scanf("%d %d\n",&n,&m);
//citim cele n elemente ale sirului initial
for(i=1;i<=n;i++)
{
scanf("%d",&j);
update(1,1,n,i,i,j); //salvam in arbore
}
//citim cele m operatii
for(i=1;i<=m;i++)
{
scanf("%d %d %d\n",&j,&a,&b);
if(j) update(1,1,n,a,a,b); //daca avem de ffacut un update
else printf("%d\n",query(1,1,n,a,b)); //afisem valoarea maxima din interval
}
fclose(stdin);
fclose(stdout);
return 0;
}