#include <bits/stdc++.h>
using namespace std;
ifstream fin ( "heavypath.in");
ofstream fout ( "heavypath.out" );
#define cin fin
#define cout fout
#define PB push_back
#define F first
#define S second
#define FR( a, b) for( int a = 0; a < (int) b; a ++ )
#define FOR( a, c, b) for( int a = c; a < (int) b; a ++ )
const int Nmax = 1e5 + 1;
const int Log = 17;
struct node {
int val;
int path, poz_aint;
int adancime = -1, parinte;
int sz = 1;
};
int aint[4 * Nmax], ce_nod[Nmax], parinte[Log][Nmax];
node v[Nmax];
vector< vector<int> > path;
vector< int > adj[Nmax];
void print_node( node nod ) {
cout << " Nod\n" << nod.val << " parinte " << nod.parinte << " adancime " << nod.adancime << " poz_aint " << nod.poz_aint << " path " << nod.path << " sz " << nod.sz << '\n';
}
bool cmp( int a, int b ) {
return v[a].adancime > v[b].adancime;
}
void dfs( int nod, int parinte ) {
int heavy_son, sz_heavy;
v[nod].adancime = v[parinte].adancime + 1;
v[nod].parinte = parinte;
if( adj[nod].size() == 1 && nod != 1 ) {
path.push_back( {nod} );
v[nod].sz = 1;
v[nod].path = path.size() - 1;
} else {
sz_heavy = 0;
FR( i, adj[nod].size() ) {
int son = adj[nod][i];
if ( son != parinte ) {
dfs( son, nod );
v[nod].sz += v[son].sz;
if( v[son].sz > sz_heavy ) {
sz_heavy = v[son].sz;
heavy_son = son;
}
}
}
v[nod].path = v[heavy_son].path;
path[ v[nod].path ].PB( nod );
}
}
void sort_paths() {
int prev_len = 1;
FR( i, path.size() ) {
sort( path[i].begin(), path[i].end(), cmp );
/*cout << i << " suntem in sort " << '\n';
FR( j, path[i].size() )
cout << path[i][j] << " ";
cout << '\n';*/
FR( j, path[i].size() ) {
int nod = path[i][j];
v[nod].poz_aint = prev_len + j;
ce_nod[prev_len + j] = nod;
}
prev_len += path[i].size();
}
}
void init( int l_range, int r_range, int poz ) {
if( l_range == r_range ) {
aint[poz] = v[ ce_nod[l_range] ].val;
return;
}
int mij = ( l_range + r_range ) / 2;
init( l_range, mij, 2 * poz );
init( mij + 1, r_range, 2 * poz + 1 );
aint[poz] = max( aint[2 * poz], aint[2 * poz + 1] );
}
void update( int l_range, int r_range, int target, int poz, int val ) {
if ( l_range > target || r_range < target )
return;
if( l_range == r_range ) {
aint[poz] = val;
return;
}
int mij = ( l_range + r_range ) / 2;
update( l_range, mij, target, 2 * poz, val );
update( mij + 1, r_range, target, 2 * poz + 1, val );
aint[poz] = max( aint[2 * poz], aint[2 * poz + 1] );
}
int query( int l_range, int r_range, int l_target, int r_target, int poz ) {
if ( l_range > r_target || r_range < l_target )
return 0;
if( l_range >= l_target && r_range <= r_target )
return aint[poz];
int mij = ( l_range + r_range ) / 2;
int a = query( l_range, mij, l_target, r_target, 2 * poz );
int b = query( mij + 1, r_range, l_target, r_target, 2 * poz + 1);
return max( a, b );
}
int lca( int u, int nod ) {
if( v[u].adancime < v[nod].adancime )
swap( u, nod );
int lev_dif = v[u].adancime - v[nod].adancime, de_urcat = 0;
while( lev_dif > 0 ) {
if( lev_dif % 2 == 1 )
u = parinte[de_urcat][u];
lev_dif /= 2;
de_urcat++;
}
if( u == nod )
return u;
de_urcat = Log;
for( de_urcat = Log - 1; de_urcat >= 0; de_urcat-- )
if( parinte[de_urcat][u] != parinte[de_urcat][nod] )
u = parinte[de_urcat][u], nod = parinte[de_urcat][nod];
return parinte[0][u];
}
int query_nodParinte( int u, int parent ) {
int ans = 0, pathU;
while( v[u].path != v[parent].path ) {
pathU = v[u].path;
int r = path[pathU][path[pathU].size() - 1];
ans = max( ans, query( 1, Nmax, v[u].poz_aint, v[r].poz_aint, 1 ) );
u = v[r].parinte;
}
ans = max( ans, query( 1, Nmax, v[u].poz_aint, v[parent].poz_aint, 1 ) );
return ans;
}
int real_query( int u, int nod ) {
int lca1 = lca( u, nod );
return max( query_nodParinte(u, lca1), query_nodParinte( nod, lca1 ) );
}
int main()
{
int n, queries, tip, val, nod, u;
cin >> n >> queries;
FOR( i, 1, n + 1 )
cin >> v[i].val;
FR( i, n - 1 ) {
cin >> u >> nod;
adj[u].PB( nod );
adj[nod].PB( u );
}
dfs( 1, 0 );
sort_paths();
FOR( i, 1, n + 1 )
parinte[0][i] = v[i].parinte;
FOR( i, 1, Log ) {
FOR( nod, 1, n + 1 )
parinte[i][nod] = parinte[i - 1][parinte[i-1][nod]];
}
/*FOR( i, 1, n + 1 )
print_node( v[i] );*/
init( 1, Nmax, 1 );
//cout << "LCA " << lca( 9, 4 ) << '\n';
while( queries-- ) {
cin >> tip >> nod;
if( tip == 0 ) {
cin >> val;
update( 1, Nmax, v[nod].poz_aint, 1, val );
} else {
cin >> u;
cout << real_query( nod, u ) << '\n';
}
}
return 0;
}