/**
* Code by Patrick Sava
* "Spiru Haret" National College of Bucharest
**/
# include "fstream"
# include "cstring"
# include "vector"
# include "queue"
# include "bitset"
# include "algorithm"
# include "map"
# include "set"
# include "unordered_map"
# include "deque"
# include "string"
# include "iomanip"
# include "cmath"
# include "stack"
# include "cassert"
const char IN [ ] = "arbint.in" ;
const char OUT [ ] = "arbint.out" ;
# define pb push_back
# define mp make_pair
# define FORN( a , b , c ) for ( int a = b ; a <= c ; ++ a )
# define FORNBACK( a , b , c ) for ( int a = b ; a >= c ; -- a )
using namespace std ;
const int MAX = 2e5 + 14 ;
ifstream cin ( IN ) ;
ofstream cout ( OUT ) ;
struct Treap {
int l , r , sz , maxim , val ;
int p ;
Treap ( )
{
p = rand ( ) + 1 ;
}
};
Treap T [ MAX ] ;
int R , noduri ;
void update ( int nod )
{
if ( nod == 0 ) return ;
T [ nod ].sz = T [ T [ nod ].l ].sz + T [ T [ nod ].r ].sz + 1 ;
T [ nod ].maxim = max ( T [ nod ].val , max ( T [ T [ nod ].l ].maxim , T [ T [ nod ].r ].maxim ) ) ;
}
int poz ( int nod )
{
return T [ T [ nod ].l ].sz + 1 ;
}
void split ( int root , int &l , int &r , int pos )
{
if ( root == 0 ){
l = r = 0 ;
}
else {
int ch = poz ( root ) ;
if ( ch >= pos ){
split ( T [ root ].l , l , T [ root ].l , pos ) ;
r = root ;
}
else {
split ( T [ root ].r , T [ root ].r , r , pos - ch ) ;
l = root ;
}
}
update ( root ) ;
}
void join ( int &root , int l , int r )
{
if ( !l or !r ) root = l + r ;
else {
if ( T [ l ].p >= T [ r ].p ){
join ( T [ l ].r , T [ l ].r , r ) ;
root = l ;
}
else {
join ( T [ r ].l , l , T [ r ].l ) ;
root = r ;
}
}
update ( root ) ;
}
void insertt ( int &root , int nod , int pos )
{
int ch = poz ( root ) ;
if ( T [ root ].p >= T [ nod ].p )
{
if ( ch >= pos )
insertt ( T [ root ].l , nod , pos ) ;
else insertt ( T [ root ].r , nod , pos - ch ) ;
}
else {
split ( root , T [ nod ].l , T [ nod ].r , pos ) ;
root = nod ;
}
update ( root ) ;
}
void erasee ( int &root , int pos )
{
int ch = poz ( root ) ;
if ( ch == pos )
join ( root , T [ root ].l , T [ root ].r ) ;
else if ( ch >= pos )
erasee ( T [ root ].l , pos ) ;
else erasee ( T [ root ].r , pos - ch ) ;
update ( root ) ;
}
int Query ( int root , int st , int dr )
{
/// intervalul [ 1 , size ]
int a = 1 ;
int b = T [ root ].sz ;
if ( b < st or a > dr ) return 0 ; /// disjuncte
if ( st <= a and b <= dr )
return T [ root ].maxim ;
int r = 0 ;
int ch = poz ( root ) ;
r = max ( r , Query ( T [ root ].l , st , dr ) ) ;
r = max ( r , Query ( T [ root ].r , st - ch , dr - ch ) ) ;
if ( st <= ch and ch <= dr ) r = max ( r , T [ root ].val ) ;
return r ;
}
int main ( void )
{
T [ 0 ].val = T [ 0 ].p = 0 ;
int n , m ;
cin >> n >> m ;
FORN ( i , 1 , n )
{
int x ;
cin >> x ;
T [ ++ noduri ].val = x ;
insertt ( R , noduri , i ) ;
}
while ( m -- )
{
int op ;
cin >> op ;
if ( op )
{
int a , b ;
cin >> a >> b ;
T [ ++ noduri ].val = b ;
erasee ( R , a ) ;
insertt ( R , noduri , a ) ;
//insert
}
else {
int a , b ;
cin >> a >> b ;
cout << Query ( R , a , b ) << '\n' ;
//query
}
}
return 0;
}