#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
template <class T>
class Parser
{
public:
Parser()
{
buffer = new char[BUFFER_SIZE];
position = BUFFER_SIZE;
}
T getNumber( istream &f )
{
return getNr( f );
}
private:
static const int BUFFER_SIZE = ( 1 << 20 );
int position;
char *buffer;
char getChar( istream &f )
{
if ( position == BUFFER_SIZE )
{
f.read( buffer, BUFFER_SIZE );
position = 0;
}
return buffer[ position++ ];
}
T getNr( istream &f )
{
T nr = (T)0;
T sgn = (T)1;
char ch;
do
{
ch = getChar( f );
if ( ch == '-' ) break;
} while ( !isdigit( ch ) );
if ( ch == '-' )
{
sgn = (T)-1;
ch = getChar( f );
}
do
{
nr = nr * (T)10 + ( ch - '0' );
ch = getChar( f );
if ( ch == '.' ) break;
} while ( isdigit( ch ) );
T pw10 = (T)10;
if ( ch == '.' )
{
ch = getChar( f );
do
{
nr = ( nr * pw10 + ( ch - '0' ) ) / pw10;
pw10 *= (T)10;
ch = getChar( f );
} while( isdigit( ch ) );
}
return ( nr * sgn );
}
};
template <class T, T(*combine)(T,T), void(*lazy)(T&)>
class SegmentTree
{
private:
int N;
T *A;
public:
SegmentTree(){}
SegmentTree( const int n, const vector <T> &v )
{
alloc_memory( n, v );
}
void alloc_memory( const int n, const vector <T> &v )
{
N = n;
A = new T[4 * N];
build( 1, 0, N - 1, v );
}
void free_memory()
{
delete A;
}
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( const 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");
Parser <int> P;
N = P.getNumber( f );
M = P.getNumber( f );
for ( int i = 0, val; i < N; ++i )
{
val = P.getNumber( f );
v.push_back( Node( val ) );
}
SegmentTree <Node, combine, lazy> ST;
ST.alloc_memory( N, v );
for ( int i = 0, tip, a, b; i < M; ++i )
{
tip = P.getNumber( f );
a = P.getNumber( f );
b = P.getNumber( f );
if ( tip == 0 )
{
a--; b--;
g << ST.query( a, b ).val << "\n";
}
else
{
a--;
ST.update( a, Node( b ) );
}
}
ST.free_memory();
return 0;
}