#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
template <class T, T(*combine)(T,T), void(*lazy)(T&)>
class SegmentTree
{
private:
int N;
T *A;
public:
SegmentTree( const int n, const vector <T> &v )
{
N = n;
A = new T[4 * N];
build( 1, 0, N - 1, v );
}
int LS( int nod )
{
return 2 * nod;
}
int RS( int nod )
{
return 2 * nod + 1;
}
int mid( int i, int j )
{
return ( i + j ) / 2;
}
void update( int pos, const T &NN )
{
update( 1, 0, N - 1, pos, NN );
}
T query( const int x, const int y )
{
return query( 1, 0, N - 1, x, y );
}
void build( int nod, int st, int dr, const vector <T> &v )
{
if ( st == dr )
{
A[nod] = v[st];
}
else
{
int m = mid( st, dr );
build( LS( nod ), st, m, v );
build( RS( nod ), m + 1, dr, v );
A[nod] = combine( A[ LS( nod ) ], A[ RS( nod ) ] );
}
}
void update( int nod, int st, int dr, int pos, const T &NN )
{
if ( st == dr )
{
A[nod] = NN;
}
else
{
lazy( A[nod] );
int m = mid( st, dr );
if ( pos <= m ) update( LS( nod ), st, m, pos, NN );
else update( RS( nod ), m + 1, dr, pos, NN );
A[nod] = combine( A[ LS( nod ) ], A[ RS( nod ) ] );
}
}
T query( int nod, int st, int dr, int st_q, int dr_q )
{
if ( st_q <= st && dr <= dr_q )
{
return A[nod];
}
else
{
lazy( A[nod] );
int m = mid( st, dr );
T sol;
if ( st_q <= m ) sol = combine( sol, query( LS( nod ), st, m, st_q, dr_q ) );
if ( m < dr_q ) sol = combine( sol, query( RS( nod ), m + 1, dr, st_q, dr_q ) );
return sol;
}
}
};
class Node
{
public:
int val;
Node( const int _val = 0 )
{
val = _val;
}
};
Node combine( Node A, Node B )
{
Node C;
C.val = max( A.val, B.val );
return C;
}
void lazy( Node &A )
{
}
int N, M;
vector <Node> v;
int main()
{
ifstream f("arbint.in");
ofstream g("arbint.out");
f >> N >> M;
for ( int i = 0, val; i < N; ++i )
{
f >> val;
v.push_back( Node( val ) );
}
SegmentTree <Node, combine, lazy> ST( N, v );
for ( int i = 0, tip, a, b; i < M; ++i )
{
f >> tip >> a >> b;
if ( tip == 0 )
{
a--; b--;
g << ST.query( a, b ).val << "\n";
}
else
{
a--;
ST.update( a, Node( b ) );
}
}
return 0;
}