#include <bits/stdc++.h>
using namespace std;
ifstream fin ("arbint.in");
ofstream fout ("arbint.out");
int aint[400005], v[100005];
int n, q, sol;
int t, a, b;
void query(int nod, int st, int dr, int left, int right){
///intervalul este cuprins intre a si b
if(left <= st && dr <= right){
sol = max(sol, aint[nod]);
return;
}
///caut in stanga
int md=(st+dr)/2;
if(left <= md)
query(2*nod, st, md, left, right);
///caut in dreapta
if(right > md)
query(2*nod+1, md+1, dr, left, right);
}
void update(int nod, int st, int dr, int poz, int k){
///ma aflu in nodul nod
///verific intervalul (st, dr)
///vreau sa pun k pe pozitia poz
///am ajuns la poz
if(st == dr){
aint[nod]=k;
return;
}
///ma apropii de poz
int md=(st+dr)/2;
if(poz <= md)
update(2*nod, st, md, poz, k); ///ma duc in stanga
if(poz > md)
update(2*nod+1, md+1, dr, poz, k); ///ma duc in dreapta
///updatez maximele
aint[nod] = max(aint[2*nod], aint[2*nod+1]);
}
void build(int nod, int st, int dr){
///pun frunza st
if(st == dr){
aint[nod]=v[st];
return;
}
int md=(st+dr)/2;
build(2*nod, st, md); ///stanga
build(2*nod+1, md+1, dr); ///dreapta
aint[nod] = max(aint[2*nod], aint[2*nod+1]); ///formez maximele
}
int main (){
fin>>n>>q;
for(int i=1; i<=n; i++)
fin>>v[i];
build(1, 1, n);
for(int qq=1; qq<=q; qq++){
fin>>t>>a>>b;
if(t == 0){
sol=0;
query(1, 1, n, a, b);
fout<<sol<<"\n";
}else{
update(1, 1, n, a, b);
}
}
return 0;
}
/*
1(1, 8)
2(1, 4) 3(5, 8)
4(1, 2) 5(3, 4) 6(5, 6) 7(7, 8)
8(1, 1) 9(2, 2) 10(3, 3) 11(4, 4) 12(5, 5) 13(6, 6) 14(7, 7) 15(8, 8)
*/