#include <fstream>
#include <vector>
using namespace std;
ifstream cin("arbint.in");
ofstream cout("arbint.out");
int n,m;
vector<int> v,tree;
void read(){
cin>>n>>m;
v.resize(n+1);
tree.resize(2*n+2);
for(int i=1;i<=n;i++){
cin>>v[i];
}
}
void buildMaxTree(int l,int r,int node){
if(l==r){
tree[node]=v[l];
return;
}
int mid=(l+r)/2;
buildMaxTree(l,mid,2*node);
buildMaxTree(mid+1,r,2*node+1);
tree[node]=max(tree[2*node],tree[2*node+1]);
}
bool isInside(int l1,int r1,int l2,int r2){
if((l1<=l2 && l2<=r1) && (l1<=r2 && r2<=r1)){
return true;
}
return false;
}
bool isIntersected(int l1,int r1,int l2,int r2){
if((l1<=l2 && l2<=r1) || (l1<=r2 && r2<=r1)){
return true;
}
return false;
}
int query(int l,int r,int node,int lFind,int rFind){
// cout<<"l:"<<l<<" r:"<<r<<"\n";
if(l==r && lFind<=l && l<=rFind){
return tree[node];
}
else if(l==r){
return 0;
}
if(isInside(lFind,rFind,l,r)){
// cout<<"isInside! treeVal:"<<tree[node]<<"\n\n";
return tree[node];
}
else if(!isIntersected(l,r,lFind,rFind)){
// cout<<"isNotIntersected!\n\n";
return 0;
}
else{
// cout<<"intersected\n\n";
}
int mid=(l+r)/2,val1,val2;
val1=query(l,mid,2*node,lFind,rFind);
val2=query(mid+1,r,2*node+1,lFind,rFind);
return max(val1,val2);
}
void update(int l,int r,int node,int pos,int val){
if(l==r && l==pos){
tree[node]=val;
return;
}
if(!(l<=pos && pos<=r)){
return;
}
int mid=(l+r)/2;
update(l,mid,2*node,pos,val);
update(mid+1,r,2*node+1,pos,val);
tree[node]=max(tree[2*node],tree[2*node+1]);
}
void solve(){
buildMaxTree(1,n,1);
int nrOp,a,b;
for(int i=1;i<=m;i++){
cin>>nrOp>>a>>b;
if(nrOp==0){
cout<<query(1,n,1,a,b)<<"\n";
}
else{
update(1,n,1,a,b);
}
}
}
int main(){
read();
solve();
return 0;
}