#include <bits/stdc++.h>
#define startt ios_base::sync_with_stdio(false);cin.tie(0);
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
#define FOR(n) for(int i=0;i<n;i++)
#define vt vector
#define vint vector<int>
#define all(v) v.begin(), v.end()
#define sz(a) (int)a.size()
#define MOD 1000000007
#define MOD2 998244353
#define MX 1000000000
#define nax 100005
#define MXL 1000000000000000000
#define PI 3.14159265
#define pb push_back
#define pf push_front
#define sc second
#define fr first
#define int ll
#define endl '\n'
#define ld long double
int ceildiv(int one, int two) {
if (one % two == 0) {return one / two;}
else {return one / two + 1;}
} int power(int n, int pow, int m) {
if (pow == 0) return 1;
if (pow % 2 == 0) {
ll x = power(n, pow / 2, m);
return (x * x) % m;
}
else return (power(n, pow - 1, m) * n) % m;
} int gcd(int a, int b) {
if (!b)return a;
return gcd(b, a % b);
} int factorial(int n, int mod) {
if (n > 1)
return (n * factorial(n - 1, mod)) % mod;
else
return 1;
} int lcm(int a, int b) {
return (a * b) / gcd(a, b);
} vector<int> read(int n) {vector<int> a; for (int i = 0; i < n; i++) { int x; cin >> x; a.pb(x);} return a;}vector<vector<int>> adj;void init(int n) {for (int i = 0; i <= n; i++) { vector<int> a; adj.pb(a);}}
class SegmentTree{
public:
//DEFINITIONS
int N, sz;
vector<int>tree;
//BUILDING
SegmentTree(int n)
{
N = n;
sz = 4*N;
tree.resize(sz,0);
}
SegmentTree( vector<int>&a )
{
N = a.size();
sz = 4*N+1;
tree.resize(sz,0);
build(1,1,N,a);
}
void print()
{
int cnt = 1;
int now = 0;
while(true)
{
for(int i = 0; i < pow(2, now); i++)
{
if(cnt > tree.size()-1)
{
break;
}
cout << tree[cnt] << " ";
cnt++;
}
now++;
if(cnt > tree.size()-1)
{
break;
}
cout << endl;
}
}
void build( int v, int l, int r, vector<int>&a )
{
if( l == r )
{
tree[v] = a[l-1];
return;
}
int m = l + (r-l)/2;
build( 2*v, l, m, a );
build( 2*v+1, m+1, r, a );
tree[v] = merge( tree[2*v+1], tree[2*v] );
}
//UPDATES AND QUERIES
void update( int v, int l, int r, int p, int val )
{
if( p < l || p > r ) return;
if( l == r )
{
tree[v] = val;
return;
}
int m = (r+l)/2;
update( 2*v, l, m, p, val );
update( 2*v+1, m+1, r, p, val );
tree[v] = merge( tree[2*v+1], tree[2*v] );
}
int get( int l, int r )
{
return query(1,1,N,l,r);
}
void modify( int pos, int val )
{
update(1,1,N,pos,val);
}
int query( int v, int nowl, int nowr, int l, int r)
{
if(nowl > r || nowr < l)
{
return 0;
}
if(nowl >= l && nowr <= r)
{
return tree[v];
}
return merge(query(2*v, nowl, (nowr+nowl)/2, l, r),query(2*v+1, (nowr+nowl)/2+1, nowr, l, r));
}
int merge( int x, int y )
{
return max(x, y);
}
};//ONE INDEXING!!!!!!
int32_t main() {
startt;
//freopen("strmatch.in", "r", stdin);
//freopen("strmatch.out", "w", stdout);
int n, q;
cin >> n >> q;
vint a = read(n);
SegmentTree st(a);
for(int i = 0; i < q; i++)
{
int c = 0;
cin >> c;
if(c == 0)
{
int l, r;
cin >> l >> r;
cout << st.get(l, r) << endl;
}
else
{
int ps, v;
cin >> ps >> v;
st.modify(ps, v);
}
}
}