#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
const int nmax = 1e5 + 1;
const int MAXLOG = 18;
struct info{
int size, next, parent, time, level;
};
info nod[nmax];
int vertex[nmax], aint[4 * nmax], perm_heavy[nmax], lca[MAXLOG][nmax], n;
vector <int> edges[nmax];
void init( int nod, int l, int r ) {
if( l == r ) {
aint[nod] = perm_heavy[l];
return;
}
init( 2 * nod, l, (l + r) / 2 );
init( 2 * nod + 1, (l + r) / 2 + 1, r );
aint[nod] = max( aint[2 * nod], aint[2 * nod + 1] );
}
int query( int nod, int l, int r, int lq, int rq ) {
if( r < lq || rq < l )
return 0;
if( lq <= l && r <= rq )
return aint[nod];
return max(query(2 * nod, l, (l + r) / 2, lq, rq), query(2 * nod + 1, (l + r) / 2 + 1, r, lq, rq) );
}
void update( int nod, int l, int r, int poz_update ) {
if( poz_update < l || poz_update > r )
return;
if( l == r ) {
aint[nod] = perm_heavy[l];
return;
}
update( 2 * nod, l, (l + r) / 2, poz_update );
update( 2 * nod + 1, (l + r) / 2 + 1, r, poz_update );
aint[nod] = max( aint[2 * nod], aint[2 * nod + 1] );
}
void find_size( int vf, int parinte, int lev ) {
nod[vf].level = lev;
nod[vf].parent = parinte;
nod[vf].size = 1;
if( vf != 1 && edges[vf].size() == 1 )
return;
for( int fiu: edges[vf] ) {
if( fiu == parinte )
continue;
find_size( fiu, vf, lev + 1 );
nod[vf].size += nod[fiu].size;
}
}
int timp = 1;
void find_heavy( int vf, int next ) {
int maxx = 0, max_fiu;
nod[vf].time = timp;
timp++;
nod[vf].next = next;
if( nod[vf].size == 1 )
return;
for( int i = 0; i < edges[vf].size(); i++ ) {
if( edges[vf][i] != nod[vf].parent ) {
if( nod[edges[vf][i]].size > maxx ) {
maxx = nod[edges[vf][i]].size;
max_fiu = edges[vf][i];
}
}
}
find_heavy( max_fiu, next );
for( int i = 0; i < edges[vf].size(); i++ ) {
if( edges[vf][i] != nod[vf].parent && edges[vf][i] != max_fiu )
find_heavy( edges[vf][i], edges[vf][i] );
}
}
int urca_niv( int vf, int niv ) {
int ind_p2 = 0;
while( niv > 0 ) {
if( niv % 2 == 1 )
vf = lca[ind_p2][vf];
ind_p2++;
niv /= 2;
}
return vf;
}
int find_lca( int a, int b ) {
int lev_a = nod[a].level, lev_b = nod[b].level;
if( lev_a > lev_b )
a = urca_niv( a, lev_a - lev_b );
else
b = urca_niv( b, lev_b - lev_a );
int i = MAXLOG - 1;
while( i >= 0 && a != b ) {
if( lca[i][a] != lca[i][b] ) {
a = lca[i][a];
b = lca[i][b];
}
i--;
}
if( a != b )
return lca[0][a];
return a;
}
int query_heavy( int a, int b ) {
// level[a] > level[b]
int rez = 0;
while( nod[a].next != nod[b].next ) {
//cout << a << " " << nod[a].next << " ";
//cout << nod[a].time << " " << nod[nod[a].next].time << "\n";
rez = max( rez, query( 1, 1, n, nod[nod[a].next].time, nod[a].time ) );
a = nod[nod[a].next].parent;
}
//cout << "a " << a << " " << b << "\n";
rez = max( rez, query( 1, 1, n, nod[b].time, nod[a].time ) );
return rez;
}
int main() {
ifstream cin("heavypath.in" );
ofstream cout("heavypath.out" );
int m, t, a, b;
int max1, max2;
int x, y;
cin >> n >> m;
for( int i = 1; i <= n; i++ )
cin >> vertex[i];
for( int i = 1; i < n; i++ ) {
cin >> x >> y;
edges[x].push_back(y);
edges[y].push_back(x);
}
find_size( 1, 0, 1 );
find_heavy( 1, 1 );
cout << "\n";
for( int i = 1; i <= n; i++ ) {
perm_heavy[nod[i].time] = vertex[i];
//cout << nod[i].time << " " << vertex[i] << "\n";
lca[0][i] = nod[i].parent;
}
for( int i = 1; i < MAXLOG; i++ )
for( int j = 1; j <= n; j++ )
lca[i][j] = lca[i - 1][lca[i - 1][j]];
init( 1, 1, n );
for( int i = 0; i < m; i++ ) {
cin >> t >> a >> b;
if( t == 0 ) {
vertex[a] = b;
perm_heavy[nod[a].time] = b;
update(1, 1, n, nod[a].time );
} else {
max1 = query_heavy( a, find_lca(a, b) );
max2 = query_heavy( b, find_lca(a, b) );
cout << max( max1, max2 ) << "\n";
}
}
return 0;
}