#include <fstream>
#include <vector>
using namespace std;
ifstream cin( "heavypath.in" );
ofstream cout( "heavypath.out" );
const int MAXN = 1e5 + 1;
struct SegmentTree {
int root, left, right;
int SegmentTree[ 2 * MAXN ];
void init( int minVal, int maxVal ) {
root = 1;
left = minVal;
right = maxVal;
}
void update( int nod, int l, int r, int p, int x ) {
if ( l == r ) {
SegmentTree[ nod ] = x;
return;
}
int med = ( l + r ) >> 1;
int R = nod + 2 * ( med - l + 1 );
int L = nod + 1;
if( p <= med )
update( L, l, med, p, x );
else update( R, med + 1, r, p, x );
SegmentTree[ nod ] = max( SegmentTree[ L ], SegmentTree[ R ] );
}
void update( int p, int x ) {
update( root, left, right, p, x );
}
int query( int nod, int l, int r, int lq, int rq ) {
if( r < lq || l > rq )
return 0;
if( lq <= l && r <= rq )
return SegmentTree[ nod ];
int med = ( l + r ) >> 1;
int R = nod + 2 * ( med - l + 1 );
int L = nod + 1;
return max( query( L, l, med, lq, rq ), query( R, med + 1, r, lq, rq ) );
}
int query( int l, int r ) {
return query( root, left, right, min( l, r ), max( l, r ) );
}
};
struct Heavy {
int poz;
SegmentTree maxim;
vector<int> pos, head;
vector<int> heavy, depth;
vector<int> parent, edges[ MAXN ];
int dfs( int u, int p ) {
int sizeV;
int sizeU = 1;
int maxSize = 0;
heavy[ u ] = -1;
parent[ u ] = p;
for( int v : edges[ u ] )
if( v != p ) {
depth[ v ] = depth[ u ] + 1;
sizeV = dfs( v, u );
sizeU += sizeV;
if( sizeV > maxSize ) {
maxSize = sizeV;
heavy[ u ] = v;
}
}
return sizeU;
}
void decompose( int u, int p, int h ) {
head[ u ] = h;
pos[ u ] = poz++;
if( heavy[ u ] != -1 )
decompose( heavy[ u ], u, h );
for( int v : edges[ u ] )
if( v != p && v != heavy[ u ] )
decompose( v, u, v );
}
void add_edge( int u, int v ) {
edges[ u ].push_back( v );
edges[ v ].push_back( u );
}
void init( int n ) {
pos.resize( n + 1 );
head.resize( n );
heavy.resize( n );
depth.resize( n );
parent.resize( n );
maxim.init( 0, n - 1 );
poz = 0;
dfs( 0, -1 );
decompose( 0, -1, 0 );
}
void update( int u, int val ) {
maxim.update( pos[ u ], val );
}
int query( int u, int v ) {
int rez;
rez = 0;
while( head[ u ] != head[ v ] ) {
if( depth[ head[ u ] ] > depth[ head[ v ] ] )
swap( u, v );
rez = max( rez, maxim.query( pos[ head[ v ] ], pos[ v ] ) );
v = parent[ head[ v ] ];
}
if( depth[ head[ u ] ] > depth[ head[ v ] ] )
swap( u, v );
rez = max( rez, maxim.query( pos[ v ], pos[ u ] ) );
return rez;
}
};
int val[ MAXN ];
Heavy maxim;
int n, q;
int main()
{
cin >> n >> q;
for( int i = 0; i < n; i++ )
cin >> val[ i ];
int u, v;
for( int i = 0; i < n - 1; i++ ) {
cin >> u >> v;
maxim.add_edge( u - 1, v - 1 );
}
maxim.init( n );
for( int u = 0; u < n; u++ )
maxim.update( u, val[ u ] );
int type;
while( q-- ) {
cin >> type;
cin >> u >> v;
if( type == 0 )
maxim.update( u - 1, v );
else cout << maxim.query( u - 1, v - 1 ) << '\n';
}
return 0;
}