#include <iostream>
#include <fstream>
using namespace std;
const int NMAX = 1e5;
const int INF = 2e9;
struct Seg_Tree {
int maxx;
Seg_Tree* first; Seg_Tree* second;
Seg_Tree () {
maxx = -INF;
first = second = NULL;
}
};
static inline void merge_Seg_Tree ( Seg_Tree* root, int left, int right ) {
int maxx_left = -INF;
if ( root -> first != NULL )
maxx_left = root -> first -> maxx;
int maxx_right = -INF;
if ( root -> second != NULL )
maxx_right = root -> second -> maxx;
root -> maxx = max ( maxx_left, maxx_right );
}
void update ( Seg_Tree* root, int left, int right, int pos, int value ) {
if ( left == right )
root -> maxx = value;
else {
int mid = left + ( right - left ) / 2;
if ( pos <= mid ) {
if ( root -> first == NULL )
root -> first = new Seg_Tree;
update ( root -> first, left, mid, pos, value );
}
else {
if ( root -> second == NULL )
root -> second = new Seg_Tree;
update ( root -> second, mid + 1, right, pos, value );
}
merge_Seg_Tree ( root, left, right );
}
}
int query ( Seg_Tree* root, int left, int right, int x, int y ) {
if ( x <= left && right <= y )
return root -> maxx;
int mid = left + ( right - left ) / 2;
int maxx_left = -INF;
if ( x <= mid ) {
if ( root -> first == NULL )
root -> first = new Seg_Tree;
maxx_left = query ( root -> first, left, mid, x, y );
}
int maxx_right = -INF;
if ( mid + 1 <= y ) {
if ( root -> second == NULL )
root -> second = new Seg_Tree;
maxx_right = query ( root -> second, mid + 1, right, x, y );
}
return max ( maxx_left, maxx_right );
}
int main()
{
ifstream in ( "arbint.in" );
ofstream out ( "arbint.out" );
Seg_Tree* root = new Seg_Tree;
int n, q; in >> n >> q;
for ( int i = 1; i <= n; i ++ ) {
int x; in >> x;
update ( root, 1, n, i, x );
}
for ( int i = 1; i <= q; i ++ ) {
int op; in >> op;
if ( op == 0 ) {
int left, right; in >> left >> right;
out << query ( root, 1, n, left, right ) << "\n";
}
else {
int pos, value; in >> pos >> value;
update ( root, 1, n, pos, value );
}
}
return 0;
}