#include <iostream>
#include <stdio.h>
#include <vector>
#define NMAX 100000
#define INF -1
#define LOGMAX 18
using namespace std;
int n, m;
vector<int> graph[NMAX];
int values[NMAX];
int current_poz, current_chain = 1;
int poz[NMAX], values2[NMAX];
int nochain[NMAX], head[NMAX];
int heavy[NMAX]; ///copilul nodului i care e heavy, deci toate muchiile astea sunt heavy
int depth[NMAX];
int ancestor[NMAX][LOGMAX];
int aint[2*NMAX];
void aint_build(int node, int nLeft, int nRight) {
if (nLeft == nRight) {
aint[node] = values2[nLeft];
return;
}
int nMid, leftSon, rightSon;
nMid = (nLeft + nRight) / 2;
leftSon = node + 1;
rightSon = node + 2 * (nMid - nLeft + 1);
aint_build(leftSon, nLeft, nMid);
aint_build(rightSon, nMid + 1, nRight);
aint[node] = max( aint[leftSon], aint[rightSon] );
}
int aint_query(int node, int nLeft, int nRight, int qLeft, int qRight) {
if (qLeft <= nLeft && qRight >= nRight)
return aint[node];
int nMid, leftSon, rightSon;
int result;
nMid = (nLeft + nRight) / 2;
leftSon = node + 1;
rightSon = node + 2 * (nMid - nLeft + 1);
result = 0;
if (qLeft <= nMid)
result = max( result, aint_query(leftSon, nLeft, nMid, qLeft, qRight) );
if (nMid < qRight)
result = max( result,aint_query(rightSon, nMid + 1, nRight, qLeft, qRight) );
return result;
}
void aint_update(int node, int nLeft, int nRight, int pos, int value) {
if (nLeft == nRight) {
aint[node] = value;
return;
}
int nMid, leftSon, rightSon;
nMid = (nLeft + nRight) / 2;
leftSon = node + 1;
rightSon = node + 2 * (nMid - nLeft + 1);
if (pos <= nMid)
aint_update(leftSon, nLeft, nMid, pos, value);
else
aint_update(rightSon, nMid + 1, nRight, pos, value);
aint[node] = max( aint[leftSon], aint[rightSon] );
}
int dfs1( int node ) {
int maxx, dim, aux;
maxx = 0;
dim = 1;
heavy[node] = -1;
for( unsigned int i = 0; i < graph[node].size(); i++ ) {
int b = graph[node][i];
if( b != ancestor[node][0] ) {
ancestor[b][0] = node;
aux = dfs1( b );
if( aux > maxx ) {
maxx = aux;
heavy[node] = b;
}
dim += aux;
}
}
return dim;
}
void binary_construction( int node ) {
int i;
for( int b : graph[node] ) {
if( b != ancestor[node][0] ) {
depth[b] = depth[node] + 1;
ancestor[b][0] = node;
for( i = 1; i < LOGMAX; i++ )
ancestor[b][i] = ancestor[ancestor[b][i-1]][i-1];
binary_construction( b );
}
}
}
int lca( int a, int b ) {
int i;
if( depth[a] < depth[b] )
swap( a, b );
int delta = depth[a] - depth[b];
for( i = LOGMAX - 1; i >= 0; i-- )
if( delta & ( 1 << i ) )
a = ancestor[a][i];
if( a == b )
return a;
for( i = LOGMAX - 1; i >= 0; i-- ) {
if( ancestor[a][i] != ancestor[b][i] ) {
a = ancestor[a][i];
b = ancestor[b][i];
}
}
return ancestor[a][0];
}
void decompose( int node ) {
unsigned int i;
int b;
poz[node] = current_poz;
current_poz++;
values2[poz[node]] = values[node];
nochain[node] = current_chain;
if( heavy[node] != -1 ) {
decompose( heavy[node] );
}
//printf( "%d\n", heavy[12] );
for( i = 0; i < graph[node].size(); i++ ) {
b = graph[node][i];
if( b != ancestor[node][0] && b != heavy[node] ) {
current_chain++;
head[current_chain] = b;
decompose( b );
}
}
}
int querytolca( int start, int finish ) {
int retval = 0;
while( nochain[start] != nochain[finish] ) {
retval = max( retval, aint_query( 0, 0, n - 1, poz[head[nochain[start]]], poz[start] ) );
start = ancestor[head[nochain[start]]][0];
}
retval = max( retval, aint_query( 0, 0, n - 1, poz[finish], poz[start] ) );
return retval;
}
void update( int node, int val ) {
values2[poz[node]] = val;
aint_update( 0, 0, n - 1, poz[node], val );
}
int query( int a, int b ) {
int x = lca( a, b );
return max( querytolca( a, x ), querytolca( b, x ) );
}
int main() {
FILE *fin, *fout;
int i, a, b, cer;
fin = fopen( "heavypath.in", "r" );
fout = fopen( "heavypath.out", "w" );
fscanf( fin, "%d%d", &n, &m );
for( i = 0; i < n; i++ )
fscanf( fin, "%d", &values[i] );
for( i = 0; i < n - 1; i++ ) {
fscanf( fin, "%d%d", &a, &b );
a--, b--;
graph[a].push_back( b );
graph[b].push_back( a );
}
ancestor[0][0] = INF; ///consider radacina in nodul 0
dfs1( 0 );
// printf( "%d %d\n", parent[12], heavy[12] );
// printf( "%d %d\n", parent[33], heavy[33] );
// printf( "%d %d\n", parent[247], heavy[247] );
binary_construction( 0 );
decompose( 0 );
aint_build( 0, 0, n - 1 );
/*
for( i = 0; i < n; i++ )
printf( "%d ", heavy[i] );
*/
for( i = 0; i < m; i++ ) {
fscanf( fin, "%d%d%d", &cer, &a, &b );
if( cer == 0 )
update( a - 1, b );
else
fprintf( fout, "%d\n", query( a - 1, b - 1 ) );
}
fclose( fin );
fclose( fout );
return 0;
}