/**
* 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 "unordered_map"
# include "deque"
# include "string"
# include "iomanip"
# include "cmath"
# include "stack"
# include "cassert"
const char IN [ ] = "heavypath.in" ;
const char OUT [ ] = "heavypath.out" ;
const int MAX = 100500 ;
# 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 ;
ifstream cin ( IN ) ;
ofstream cout ( OUT ) ;
vector < int > gr [ MAX ] ;
vector < int > lant [ MAX ] ;
vector < int > AINT [ MAX ] ;
int lantdenod [ MAX ] , val [ MAX ] , nivel [ MAX ] , tata [ MAX ] , nr_lant , sub [ MAX ] , poz [ MAX ] ;
inline void dfs ( int nod , int boss , int lvl )
{
nivel [ nod ] = lvl ;
sub [ nod ] = 1 ;
for ( auto x : gr [ nod ] )
if ( x != boss )
{
tata [ x ] = nod ;
dfs ( x , nod , lvl + 1 ) ;
sub [ nod ] += sub [ x ] ;
}
if ( gr [ nod ].size ( ) == 1 and nod != 1 )
{
++ nr_lant ;
lant [ nr_lant ].pb ( 0 ) ;
lant [ nr_lant ].pb ( nod ) ;
lantdenod [ nod ] = nr_lant ;
poz [ nod ] = 1 ;
return ;
}
int CET = 0 ;
for ( auto x : gr [ nod ] )
{
if ( x != boss and sub [ x ] > sub [ CET ] )
CET = x ;
}
lantdenod [ nod ] = lantdenod [ CET ] ;
lant [ lantdenod [ nod ] ].pb ( nod ) ;
poz [ nod ] = lant [ lantdenod [ nod ] ].size ( ) - 1 ;
}
inline void build ( int lantz , int nod , int st , int dr )
{
if ( st == dr ){
AINT [ lantz ] [ nod ] = val [ lant [ lantz ] [ st ] ] ;
return ;
}
int mij = ( st + dr ) >> 1 ;
build ( lantz , nod << 1 , st , mij ) ;
build ( lantz , nod << 1 | 1 , mij + 1 , dr ) ;
AINT [ lantz ] [ nod ] = max ( AINT [ lantz ] [ nod << 1 ], AINT [ lantz ] [ nod << 1 | 1 ] ) ;
}
inline void update ( int lantz , int nod , int st , int dr , int pos , int valuee )
{
if ( st == dr )
{
AINT [ lantz ] [ nod ] = valuee ;
return ;
}
int mij = ( st + dr ) >> 1 ;
if ( pos <= mij )
update ( lantz , nod << 1 , st , mij , pos , valuee ) ;
else update ( lantz , nod << 1 | 1 , mij + 1 , dr , pos , valuee ) ;
AINT [ lantz ] [ nod ] = max ( AINT [ lantz ] [ nod << 1 ], AINT [ lantz ] [ nod << 1 | 1 ] ) ;
}
inline int query ( int lantz , int nod , int st , int dr , int a , int b )
{
if ( a <= st and dr <= b )
{
return AINT [ lantz ] [ nod ] ;
}
int mij = ( st + dr ) >> 1 ;
int kk1 = - ( 1 << 30 ) , kk2 = - ( 1 << 30 ) ;
if ( a <= mij )
kk1 = query ( lantz , nod << 1 , st , mij , a , b ) ;
if ( b > mij )
kk2 = query ( lantz , nod << 1 | 1 , mij + 1 , dr , a , b ) ;
return max ( kk1 , kk2 ) ;
}
int solve ( int x , int y )
{
int CET = - 14 ;
while ( 1 )
{
int xx = lantdenod [ x ] ;
int yy = lantdenod [ y ] ;
if ( xx == yy )
{
int a = min ( poz [ x ] , poz [ y ] ) ;
int b = max ( poz [ x ] , poz [ y ] ) ;
CET = max ( CET , query ( xx , 1 , 1 , lant [ xx ].size ( ) - 1 , a , b ) ) ;
break ;
}
int bossa = lant [ xx ] [ 1 ] ;
int bossb = lant [ yy ] [ 1 ] ;
if ( nivel [ bossa ] < nivel [ bossb ] )
swap ( x , y ) ;
xx = lantdenod [ x ] ;
yy = lantdenod [ y ] ;
CET = max ( CET , query ( xx , 1 , 1 , lant [ xx ].size ( ) - 1 , 1 , poz [ x ] ) ) ;
x = tata [ lant [ xx ] [ 1 ] ] ;
}
return CET ;
}
int main ( void )
{
int n , m ;
cin >> n >> m ;
FORN ( i , 1 , n )
cin >> val [ i ] ;
FORN ( i , 2 , n )
{
int x , y ;
cin >> x >> y ;
gr [ x ].pb ( y ) ;
gr [ y ].pb ( x ) ;
}
dfs ( 1 , 0 , 0 ) ;
FORN ( i , 1 , nr_lant )
{
reverse ( lant [ i ].begin ( ) + 1 , lant [ i ].end ( ) ) ;
AINT [ i ].resize ( 4 * lant [ i ].size ( ) ) ;
build ( i , 1 , 1 , lant [ i ].size ( ) - 1 ) ;
}
FORN ( i , 1 , n )
poz [ i ] = lant [ lantdenod [ i ] ].size ( ) - poz [ i ] ;
while ( m -- )
{
int tip , x , y ;
cin >> tip >> x >> y ;
if ( tip == 0 )
{
update ( lantdenod [ x ] , 1 , 1 , lant [ lantdenod [ x ] ].size ( ) - 1 , poz [ x ] , y ) ;
}
else cout << solve ( x , y ) << '\n' ;
}
return 0;
}