/*
* Code by Spiromanul
*/
#include <fstream>
#include <vector>
#include <algorithm>
#define pb push_back
const char IN [ ] = "heavypath.in" ;
const char OUT [ ] = "heavypath.out" ;
const int MAX = 100014 ;
using namespace std;
ifstream fin ( IN ) ;
ofstream fout ( OUT ) ;
int val [ MAX ] , level [ MAX ] , subarbore [ MAX ] , tata [ MAX ] ;
int lant [ MAX ] , drum , indexlant [ MAX ] ;
vector < int > gr [ MAX ] ;
vector < int > L [ MAX ] ;
vector < int > AINT [ MAX ] ;
//////////////////////////////////////////////////// depth-first search begin
inline void dfs ( int nod , int lvl , int boss )
{
level [ nod ] = lvl ;
subarbore [ nod ] = 1 ;
for ( auto x : gr [ nod ] )
if ( x != boss )
{
tata [ x ] = nod ;
dfs ( x , lvl + 1 , nod ) ;
subarbore [ nod ] += subarbore [ x ] ;
}
if ( gr [ nod ].size ( ) == 1 and nod != 1 )
{
++ drum ;
lant [ nod ] = drum ;
L [ drum ].pb ( 0 ) ;
L [ drum ].pb ( nod ) ;
indexlant [ nod ] = 1 ;
return ;
}
int ce_trebuie = 0 ;
for ( auto x : gr [ nod ] )
if ( x != boss and subarbore [ x ] > subarbore [ ce_trebuie ] )
ce_trebuie = x ;
lant [ nod ] = lant [ ce_trebuie ] ;
L [ lant [ nod ] ].pb ( nod ) ;
indexlant [ nod ] = L [ lant [ nod ] ].size ( ) - 1 ;
}
//////////////////////////////////////////////////// depth-first search end
/////////////////////////////////////////////////// building begin
inline void building ( int nod , int st , int dr , int indice )
{
if ( st == dr )
{
AINT [ indice ] [ nod ] = val [ L [ indice ] [ st ] ] ;
return ;
}
int mij = ( st + dr ) >> 1 ;
building ( nod << 1 , st , mij , indice ) ;
building ( nod << 1 | 1 , mij + 1 , dr , indice ) ;
AINT [ indice ] [ nod ] = max ( AINT [ indice ] [ nod << 1 ] , AINT [ indice ] [ nod << 1 | 1 ] ) ;
}
/////////////////////////////////////////////////// building end
////////////////////////////////////////////////// update poz begin
int update_poz , val_de_updatat ;
inline void update ( int nod , int st , int dr , int indice )
{
if ( st == dr )
{
AINT [ indice ] [ nod ] = val_de_updatat ;
return ;
}
int mij = ( st + dr ) >> 1 ;
if ( update_poz <= mij )
update ( nod << 1 , st , mij , indice ) ;
else update ( nod << 1 | 1 , mij + 1 , dr , indice ) ;
AINT [ indice ] [ nod ] = max ( AINT [ indice ] [ nod << 1 ] , AINT [ indice ] [ nod << 1 | 1 ] ) ;
}
////////////////////////////////////////////////// update poz end
////////////////////////////////////////////////// query begin
int a , b ;
inline void query ( int nod , int st , int dr , int indice , int &ans )
{
if ( a <= st and dr <= b )
{
ans = max ( ans , AINT [ indice ] [ nod ] ) ;
return ;
}
int mij = ( st + dr ) >> 1 ;
if ( a <= mij )
query ( nod << 1 , st , mij , indice , ans ) ;
if ( b > mij )
query ( nod << 1 | 1 , mij + 1 , dr , indice , ans ) ;
}
////////////////////////////////////////////////// query end
////////////////////////////////////////////////// gasesc maximul begin
inline int do_the_job ( int x , int y )
{
int ans = 0 ;
while ( 14 )
{
if ( lant [ x ] == lant [ y ] )
{
a = min ( indexlant [ x ] , indexlant [ y ] ) ;
b = max ( indexlant [ x ] , indexlant [ y ] ) ;
query ( 1 , 1 , ( int ) L [ lant [ x ] ].size ( ) - 1 , lant [ x ] , ans ) ;
break ;
}
int x1 = L [ lant [ x ] ] [ 1 ] ;
int y1 = L [ lant [ y ] ] [ 1 ] ;
if ( level [ x1 ] < level [ y1 ] )
swap ( x , y ) ;
a = 1 ;
b = indexlant [ x ] ;
query ( 1 , 1 , ( int ) L [ lant [ x ] ].size ( ) - 1 , lant [ x ] , ans ) ;
x = tata [ L [ lant [ x ] ] [ 1 ] ] ;
}
return ans ;
}
////////////////////////////////////////////////// gasesc maximul end
int main ( )
{
int n , m ;
fin >> n >> m ;
for ( int i = 1 ; i <= n ; ++ i )
fin >> val [ i ] ;
for ( int i = 1 ; i < n ; ++ i )
{
int x , y ;
fin >> x >> y ;
gr [ x ].pb ( y ) ;
gr [ y ].pb ( x ) ;
}
dfs ( 1 , 1 , 0 ) ;
for ( int i = 1 ; i <= drum ; ++ i )
{
reverse ( L [ i ].begin ( ) + 1 , L [ i ].end ( ) ) ;
AINT [ i ].resize ( 4 * ( L [ i ].size ( ) + 1 ) ) ;
building ( 1 , 1 , ( int ) L [ i ].size ( ) - 1 , i ) ;
}
for ( int i = 1 ; i <= n ; ++ i )
indexlant [ i ] = L [ lant [ i ] ].size ( ) - indexlant [ i ] ;
for ( ; m ; -- m )
{
int tip , x , y ;
fin >> tip >> x >> y ;
if ( tip == 0 )
{
update_poz = indexlant [ x ] ; val_de_updatat = y ;
update ( 1 , 1 , L [ lant [ x ] ].size ( ) - 1 , lant [ x ] ) ;
}
else {
fout << do_the_job ( x , y ) << '\n' ;
}
}
return 0;
}