#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <deque>
#include <iomanip>
#include <vector>
#pragma GCC optimize("O3")
#define fi first
#define se second
#define pb push_back
#define pf push_front
using namespace std;
ifstream fin ("arbint.in");
ofstream fout ("arbint.out");
typedef long long ll;
const ll Nmax=1e5+5, inf=1e9+5;
using pll=pair<ll, ll>;
///point update / range querry
struct AINT{
vector <int> st;
void build (int nod, int l, int r, int v[]){
if (l==r){
st[nod]=v[l];
return;
}
int mij=(l+r)/2;
build (nod*2, l, mij, v);
build (nod*2+1, mij+1, r, v);
st[nod]=max(st[nod*2], st[nod*2+1]);
}
AINT (int n, int v[]){
st.resize(n*4);
build(1, 0, n-1, v);
}
void update (int nod, int l, int r, int ind, int val){
if (l==r){
st[nod]=val;
return;
}
int mij=(l+r)/2;
if (l<=ind && ind<=mij)
update (nod*2, l, mij, ind, val);
else update (nod*2+1, mij+1, r, ind, val);
st[nod]=max(st[nod*2], st[nod*2+1]);
}
int querry (int nod, int l, int r, int lq, int rq){
if (rq<l || lq>r)
return 0;
if (lq<=l && r<=rq)
return st[nod];
int mij=(l+r)/2;
return max(querry(nod*2, l, mij, lq, rq), querry(nod*2+1, mij+1, r, lq, rq));
}
};
int v[Nmax];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, m;
fin>>n>>m;
for (int i=0; i<n; i++)
fin>>v[i];
AINT aint(n, v);
int t, a, b;
for (int i=0; i<m; i++){
fin>>t>>a>>b;
if (t==0){
a--; b--;
fout<<aint.querry(1, 0, n-1, a, b)<<'\n';
}
else{
a--;
aint.update(1, 0, n-1, a, b);
}
}
return 0;
}