// LPD
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int NR = 100005 ;
ofstream out ("heavypath.out") ;
vector < int > v [ NR ] , lant [ NR ] , aint [ NR ] ;
int n , q , c [ NR ] , nr_fii [ NR ] , lvl [ NR ] , nr_lant , pos [ NR ] ,w_l [ NR ] , father [ NR ] ;
class InParser {
private:
FILE *fin;
char *buff;
int sp;
char read_ch() {
++sp;
if (sp == 4096) {
sp = 0;
fread(buff, 1, 4096, fin);
}
return buff[sp];
}
public:
InParser(const char* nume) {
fin = fopen(nume, "r");
buff = new char[4096]();
sp = 4095;
}
InParser& operator >> (int &n) {
char c;
while (!isdigit(c = read_ch()) && c != '-');
int sgn = 1;
if (c == '-') {
n = 0;
sgn = -1;
} else {
n = c - '0';
}
while (isdigit(c = read_ch())) {
n = 10 * n + c - '0';
}
n *= sgn;
return *this;
}
InParser& operator >> (long long &n) {
char c;
n = 0;
while (!isdigit(c = read_ch()) && c != '-');
long long sgn = 1;
if (c == '-') {
n = 0;
sgn = -1;
} else {
n = c - '0';
}
while (isdigit(c = read_ch())) {
n = 10 * n + c - '0';
}
n *= sgn;
return *this;
}
};
void dfs ( int nod , int taticut ) {
int node = 0 ;
vector < int > :: iterator it ;
nr_fii [ nod ] = 1 ;
for ( it = v [ nod ].begin() ; it != v [ nod ].end() ; ++ it ) {
if ( *it == taticut ) continue ;
lvl [ *it ] = lvl [ nod ] + 1 ;
dfs( *it , nod ) ;
// nr_fii [ nod ] += nr_fii [ *it ] ;
if ( nr_fii [ *it ] > nr_fii [ node ] ) node = *it ;
}
nr_fii [ nod ] = 1 + nr_fii [ node ] ;
if ( !node ) {
lant [ ++ nr_lant ].pb( nod ) ;
pos [ nod ] = 1 ;
w_l [ nod ] = nr_lant ;
} else {
w_l [ nod ] = w_l [ node ] ;
pos [ nod ] = 1 + pos [ node ] ;
lant [ w_l [ nod ] ].pb ( nod ) ;
}
for ( it = v [ nod ].begin() ; it != v [ nod ].end() ; ++ it ) {
if ( *it == taticut || *it == node ) continue ;
father [ w_l [ *it ] ] = nod ;
}
}
void el_update ( int lant , int nod , int st , int dr , int pos , int val ) {
if ( st == dr ) {
aint [ lant ][ nod ] = val ;
return ;
}
int mid = ( st + dr ) >> 1 ;
if ( pos <= mid ) el_update( lant , nod << 1 , st , mid , pos , val ) ;
else el_update( lant , nod << 1 | 1 , mid + 1 , dr , pos , val ) ;
aint [ lant ][ nod ] = max ( aint [ lant ][ nod << 1 ] , aint [ lant ][ nod << 1 | 1 ] ) ;
}
inline void pre_procces()
{
int i , j ;
for ( i = 1 ; i <= nr_lant ; ++i ) aint[ i ].resize( lant[ i ].size()*4 + 5 ) ;
for( i = 1 ; i <= nr_lant ; ++ i )
for( j = 0 ; j < lant[i].size() ; ++ j )
el_update ( i , 1 , 1 , lant[ i ].size() , j + 1 , c [ lant [ i ][ j ] ] ) ;
}
int query ( int lant , int nod , int st , int dr , int a , int b ) {
if ( a <= st && dr <= b ) return aint [ lant ][ nod ] ;
int mid = ( st + dr ) >> 1 , lmax = 0 , rmax = 0 ;
if ( a <= mid ) lmax = query( lant , nod << 1 , st , mid , a , b ) ;
if ( mid < b ) rmax = query( lant , nod << 1 | 1 , mid + 1 , dr , a , b ) ;
return max ( lmax , rmax ) ;
}
int main() {
InParser in ("heavypath.in") ;
int i , x , y , tip ;
in >> n >> q ;
for ( i = 1 ; i <= n ; ++ i ) in >> c [ i ] ;
for ( i = 1 ; i < n ; ++ i ) {
in >> x >> y ;
v [ x ].pb ( y ) ;
v [ y ].pb ( x ) ;
}
lvl [ 1 ] = 1 ;
dfs( 1 , 0 ) ;
pre_procces() ;
while ( q -- ) {
in >> tip >> x >> y ;
if ( !tip ) {
el_update( w_l [ x ] , 1 , 1 , lant [ w_l [ x ] ].size() , pos [ x ] , y ) ;
} else {
int sol = 0 ;
while ( w_l [ x ] != w_l [ y ] ) {
if ( lvl [ father [ w_l [ x ] ] ] < lvl [ father [ w_l [ y ] ] ] )
swap ( x , y ) ;
sol = max ( sol , query( w_l [ x ] , 1 , 1 , lant[ w_l [ x ] ].size() , pos [ x ] , lant [ w_l [ x ] ].size() ) ) ;
x = father [ w_l [ x ] ] ;
}
sol = max ( sol , query( w_l [ x ] , 1 , 1 , lant [ w_l [ x ] ].size() , min ( pos [ y ] , pos [ x ] ) , max ( pos [ x ] , pos [ y ] ) ) ) ;
out << sol << '\n' ;
}
}
}