#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
struct node {
int maxim;
int left_child;
int right_child;
};
vector <node> aint;
node empty_node = { -1, -1, -1 };
void recompute_node( int root ) {
if ( aint[root].left_child == -1 ) {
aint[root].left_child = aint.size();
aint.push_back( empty_node );
}
if ( aint[root].right_child == -1 ) {
aint[root].right_child = aint.size();
aint.push_back( empty_node );
}
}
void update ( int root, int poz, int value, int st, int dr ) {
// cout << st << ' ' << dr << endl;
recompute_node( root );
if ( st == dr ) {
aint[root].maxim = value;
return;
}
int mij = ( st + dr ) / 2;
if ( poz <= mij ) {
update( aint[root].left_child, poz, value, st, mij );
} else
update( aint[root].right_child, poz, value, mij + 1, dr );
aint[root].maxim = max( aint[aint[root].left_child].maxim,
aint[aint[root].right_child].maxim );
}
int query( int root, int st, int dr, int a, int b ) {
if ( aint[root].maxim == -1 )
return -1;
if ( st == a && dr == b ) {
return aint[root].maxim;
}
int mij = ( st + dr ) / 2;
if ( b <= mij )
return query( aint[root].left_child, st, mij, a, b );
if ( a > mij )
return query( aint[root].right_child, mij + 1, dr, a, b );
return max( query( aint[root].left_child , st, mij, a, mij ),
query( aint[root].right_child, mij + 1, dr, mij + 1, b ) );
}
int main() {
ifstream fin( "arbint.in" );
ofstream fout( "arbint.out" );
int n, i, q, a, c, b;
int root = 0;
aint.push_back( empty_node );
fin >> n >> q;
for ( i = 0; i < n; i ++ ) {
fin >> a;
update( root, i, a, 0, n - 1 );
}
// cout << aint[root].maxim << endl;;
for ( i = 0; i < q; i ++ ) {
fin >> c >> a >> b;
if ( c == 0 ) {
fout << query( root, 0, n - 1, a - 1, b - 1 ) << '\n';
} else
update( root, a - 1, b, 0, n - 1 );
}
return 0;
}