#include<fstream>
using namespace std;
ifstream fin( "arbint.in" ); ofstream fout( "arbint.out" );
const int nmax = 1e5;
struct arbint{
int val;
arbint *left, *right;
arbint() {
left = NULL;
right = NULL;
val = -1;
}
} *root;
inline int max2( int x, int y ) {
return ( x > y ? x : y );
}
inline int maxim( arbint *x ) {
return ( x == NULL ? -1 : (x -> val) );
}
void update( arbint *nod, int x, int y, int pos, int val ) {
if ( x == y ) {
nod -> val = val;
return ;
}
int mid = ( x + y ) / 2;
if ( pos <= mid ) {
if ( nod -> left == NULL ) {
nod -> left = new arbint();
}
update( nod -> left, x, mid, pos, val );
} else {
if ( nod -> right == NULL ) {
nod -> right = new arbint();
}
update( nod -> right, mid + 1, y, pos, val );
}
nod -> val = max2( maxim( nod -> left ), maxim( nod -> right ) );
}
int query( arbint *nod, int x, int y, int st, int dr ) {
if ( st <= x && y <= dr ) {
return ( maxim( nod ) );
}
int mid = ( x + y ) / 2;
int ans = -1;
if ( st <= mid && (nod -> left) != NULL ) {
ans = max2( ans, query( nod -> left, x, mid, st, dr ) );
}
if ( dr >= mid + 1 && (nod -> right) != NULL ) {
ans = max2( ans, query( nod -> right, mid + 1, y, st, dr ) );
}
return ans;
}
int main() {
int n, m;
fin >> n >> m;
root = new arbint();
for( int i = 1; i <= n; ++ i ) {
int x;
fin >> x;
update( root, 1, n, i, x );
}
for( int i = 0; i < m; ++ i ) {
int type, x, y;
fin >> type >> x >> y;
if ( type == 0 ) {
fout << query( root, 1, n, x, y ) << "\n";
} else {
update( root, 1, n, x, y );
}
}
fin.close();
fout.close();
return 0;
}