// Arbori de intervale implementati in varianta HEAPURI
#include <cstdio>
#include <fstream>
using namespace std;
#define MAX_N 100005
#define INF 100000000
int arb[MAX_N];
int N,M,i,A,B;
int ANSWER;
int MAX (int a, int b)
{
if (a<b) return b; else return a;
}
/*
void buildtree (int ind, int li, int lf)
{
int mj;
if (li==lf) arb[ind]=a[li];
else
{
mj=(li+lf)>>1;
buildtree(ind*2,li,mj);
buildtree(ind*2+1,mj+1,lf);
arb[ind]=MAX(arb[ind*2],arb[ind*2+1]);
}
}
*/
int query (int ind, int li, int lf, int A, int B)
{
int mj;
if (li>=A && lf<=B) return arb[ind];
if(lf<A || li>B)
return -INF;
mj=(li+lf)>>1;
return MAX( query(2*ind,li,mj,A,B) , query(2*ind+1,mj+1,lf,A,B) );
}
void update(int nod, int left, int right)
{
if ( left == right )
{
arb[nod] = B;
return;
}
int div = (left+right)/2;
if ( A <= div ) update(2*nod,left,div);
else update(2*nod+1,div+1,right);
arb[nod] = MAX( arb[2*nod], arb[2*nod+1] );
}
int main()
{
freopen("arbint.in","r",stdin);
freopen("arbint.out","w",stdout);
scanf("%d %d",&N,&M);
for (i=1; i<=N; i++)
{
int c;
scanf("%d",&c);
B = c;
A = i;
update (1, 1, N);
}
//buildtree(1,1,N);
for (i=1; i<=M; i++)
{
int x;
scanf("%d %d %d",&x,&A,&B);
if (!x)
{
ANSWER = query(1,1,N,A,B);
printf("%d\n",ANSWER);
}
else update (1, 1, N);
}
return 0;
}