#include <iostream>
#include <cstdio>
using namespace std;
const int NMAX = 100000;
struct Node{
int st,dr;
int maxim;
}arb[4*NMAX];
int A[NMAX];
void unite(Node &res, Node a, Node b){
res.maxim=a.maxim>b.maxim?a.maxim:b.maxim;
}
void build(int node, int st, int dr){
arb[node].st=st;
arb[node].dr=dr;
if(st==dr){
arb[node].maxim=A[st];
return;
}
int mid=(st+dr)/2;
build(2*node,st,mid);
build(2*node+1,mid+1,dr);
unite(arb[node],arb[2*node],arb[2*node+1]);
}
int MAX(int a, int b){
return a>b?a:b;
}
int query(int node, int st, int dr){
int mid=(arb[node].st+arb[node].dr)/2;
if(arb[node].st==st && arb[node].dr==dr)
return arb[node].maxim;
else if(dr<=mid)
return query(2*node,st,dr);
else if(st>mid)
return query(2*node+1,st,dr);
else
return MAX(query(2*node,st,mid),query(2*node+1,mid+1,dr));
}
void update(int node, int where, int new_value){
int mid=(arb[node].st+arb[node].dr)/2;
if(arb[node].st==arb[node].dr){
A[arb[node].st]=new_value;
arb[node].maxim=new_value;
return;
}
else if(where<=mid)
update(2*node,where,new_value);
else
update(2*node+1,where,new_value);
unite(arb[node],arb[2*node],arb[2*node+1]);
}
int main()
{
FILE *fin, *fout;
int m,n,i,a,b,tip;
fin=fopen("arbint.in","r");
fout=fopen("arbint.out","w");
fscanf(fin,"%d %d",&n,&m);
for(i=1;i<=n;i++)
fscanf(fin,"%d",&A[i]);
build(1,1,n);
for(i=1;i<=m;i++){
fscanf(fin,"%d %d %d\n",&tip,&a,&b);
if(tip==0){
fprintf(fout,"%d\n",query(1,a,b));
}
else
update(1,a,b);
}
fclose(fin);
fclose(fout);
return 0;
}