#include <bits/stdc++.h>
#define MAX_N 100000
using namespace std;
struct SGT {
int root, left, right;
int sgt[4 * MAX_N];
void init( int minVal, int maxVal ) {
root = 0;
left = minVal;
right = maxVal;
}
void update( int nod, int l, int r, int p, int x ) {
int mid;
if ( l == r ) {
sgt[nod] = x;
return;
}
mid = (l + r) / 2;
if ( p <= mid )
update( nod * 2 + 1, l, mid, p, x );
else
update( nod * 2 + 2, mid + 1, r, p, x );
sgt[nod] = max( sgt[nod * 2 + 1], sgt[nod * 2 + 2] );
}
void update( int p, int x ) {
update( root, left, right, p, x );
}
int query( int nod, int l, int r, int lq, int rq ) {
int mid;
if ( r < lq || l > rq )
return 0;
if ( lq <= l && r <= rq )
return sgt[nod];
mid = (l + r) / 2;
return max( query( nod * 2 + 1, l, mid, lq, rq ), query( nod * 2 + 2, mid + 1, r, lq, rq ) );
}
int query( int l, int r ) {
return query( root, left, right, min( l, r ), max( l, r ) );
}
};
struct HPD {
int crt_pos;
vector <int> pos, head, heavy, depth, parent, edges[MAX_N];
SGT maxim;
int dfs( int u, int p ) {
int maxSize, sizeU, sizeV;
parent[u] = p;
sizeU = 1;
maxSize = 0;
heavy[u] = -1;
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] = crt_pos++;
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 );
head.resize( n );
heavy.resize( n );
depth.resize( n );
parent.resize( n );
maxim.init( 0, n - 1 );
crt_pos = 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 ans;
ans = 0;
while ( head[u] != head[v] ) {
if ( depth[head[u]] > depth[head[v]] )
swap( u, v );
ans = max( ans, maxim.query( pos[head[v]], pos[v] ) );
v = parent[head[v]];
}
if ( depth[head[u]] > depth[head[v]] )
swap( u, v );
ans = max( ans, maxim.query( pos[v], pos[u] ) );
return ans;
}
};
int val[MAX_N];
HPD maxim;
int main() {
ifstream cin( "heavypath.in" );
ofstream cout( "heavypath.out" );
int n, m, tip, u, v, x, i;
cin >> n >> m;
for ( u = 0; u < n; u++ )
cin >> val[u];
for ( i = 0; i < n - 1; i++ ) {
cin >> u >> v;
maxim.add_edge( u - 1, v - 1 );
}
maxim.init( n );
for ( u = 0; u < n; u++ )
maxim.update( u, val[u] );
while ( m-- ) {
cin >> tip;
if ( tip == 0 ) {
cin >> u >> x;
maxim.update( u - 1, x );
} else {
cin >> u >> v;
cout << maxim.query( u - 1, v - 1 ) << "\n";
}
}
return 0;
}