/// maximul dintr-o ferestra cu m operatii de tipul
/// 1 -> v[poz] = val;
/// 2 -> care este valoarea maxima din intervalul pozitiilor x y
#include <iostream>
#include <fstream>
using namespace std;
const int N = 1e5;
const int INF = 2e9;
int v[N], seg_tree[2*N];
ifstream fin ( "arbint.in" );
ofstream fout ( "arbint.out" );
void recalculate ( int node ) {
seg_tree[node] = max ( seg_tree[2*node+1], seg_tree[2*node+2] );
}
void build ( int node, int l, int r ) {
if ( l == r )
seg_tree[node] = v[l];
else {
int mid = l + ( r - l ) / 2;
build ( 2 * node + 1, l, mid );
build ( 2 * node + 2, mid + 1, r );
recalculate ( node );
}
}
void update ( int node, int l, int r, int poz, int val ) {
if ( l == r )
seg_tree[node] = val;
else {
int mid = l + ( r - l ) / 2;
if ( poz <= mid )
update ( 2 * node + 1, l, mid, poz, val );
else
update ( 2 * node + 2, mid + 1, r, poz, val );
recalculate ( node );
}
}
int query ( int node, int l, int r, int x, int y ) {
if ( x <= l && r <= y )
return seg_tree[node];
else {
int ans = -INF;
int mid = l + ( r - l ) / 2;
if ( x <= mid )
ans = max ( ans, query ( 2 * node + 1, l, mid, x, y ) );
if ( y >= mid + 1 )
ans = max ( ans, query ( 2 * node + 2, mid + 1, r, x, y ) );
return ans;
}
}
int main()
{
int n, m;
int tip, poz, val, x, y;
fin >> n >> m;
for ( int i = 1; i <= n; i ++ )
fin >> v[i];
build ( 0, 1, n );
for ( int i = 1; i <= m; i ++ ) {
fin >> tip;
if ( tip == 1 ) {
fin >> poz >> val;
update ( 0, 1, n, poz, val );
}
else {
fin >> x >> y;
fout << query ( 0, 1, n, x, y );
fout << '\n';
}
}
return 0;
}