// This program was written by Mircea Rebengiuc
// on 02.08.2022
// for problem heavypath
#include <stdio.h>
#include <ctype.h>
#include <vector>
FILE *fin, *fout;
static inline int fgetint(){
int n = 0, ch;
while( !isdigit( ch = fgetc( fin ) ) );
do
n = n * 10 + ch - '0';
while( isdigit( ch = fgetc( fin ) ) );
return n;
}
static inline int max( int a, int b ){ return a > b ? a : b; }
#define MAXN 100000
#define MAXP2 131072
#define INF 2000000000
#define NIL -1
std::vector<int> adj[MAXN]; // lista de adiacenta
int par[MAXN]; // parinte
int depth[MAXN]; // adancime
int val[MAXN]; // valoare
//int size[MAXN]; // marimea subarborelui
int head[MAXN]; // capul lantului
int aintp[MAXN]; // indice in aint
int heavy[MAXN]; // fiul cel mai mare
char viz[MAXN];
// AINT implementation
int aint[2 * MAXP2];
int aintn;
int _query( int root, int rl, int rr, int ql, int qr ){
int mij = (rl + rr) >> 1, left = 2 * root + 1, right = 2 * root + 2;
if( rl == ql && qr == rr ) return aint[root];
if( qr <= mij ) return _query( left, rl, mij, ql, qr );
if( ql > mij ) return _query( right, mij+1, rr, ql, qr );
return max(
_query( left, rl, mij, ql, mij ),
_query( right, mij+1, rr, mij+1, qr )
);
}
// wrapper
inline __attribute__((always_inline)) int query( int ql, int qr ){
if( ql > qr )
return _query( 0, 0, aintn - 1, qr, ql );
return _query( 0, 0, aintn - 1, ql, qr );
}
void update( int index, int newval ){// update is easier iterative
int root = aintn - 1 + index;
aint[root] = newval;
while( root ){
root = (root - 1) >> 1;
aint[root] = max( aint[2 * root + 1], aint[2 * root + 2] );
}
}
// returns subtree size
int initdfs( int root ){
int maxsize = 0, csize, size = 1;
for( int child : adj[root] )
if( child != par[root] ){
par[child] = root;
depth[child] = 1 + depth[root];
csize = initdfs( child );
if( csize > maxsize ){
heavy[root] = child;
maxsize = csize;
}
size += csize;
}
return size;
}
int main(){
fin = fopen( "heavypath.in", "r" );
fout = fopen( "heavypath.out", "w" );
int n, q, i, op, a, b, qans;
n = fgetint();
q = fgetint();
for( i = 0 ; i < n ; i++ )
val[i] = fgetint();
for( i = 1 ; i < n ; i++ ){
a = fgetint() - 1;
b = fgetint() - 1;
adj[a].push_back( b );
adj[b].push_back( a );
}
for( i = 0 ; i < n ; i++ )
heavy[i] = NIL;
depth[0] = head[0] = 0;
par[0] = NIL;
initdfs( 0 );
b = 0;
for( i = 0 ; i < n ; i++ )
if( !viz[i] ){
a = i;
//printf( "heavychain:" );
while( a != NIL ){
viz[a] = 1;
aintp[a] = b++;
head[a] = i;// add head reference
//printf( " %d(%d)", a + 1, head[a] + 1 );
a = heavy[a];
}
//printf( "\n" );
}
aintn = 1;
while( aintn < n )
aintn <<= 1;
for( i = 0 ; i < n ; i++ )
update( aintp[i], val[i] );
for( ; q-- ; ){
op = fgetint();
a = fgetint() - 1;
b = fgetint() - 1;
if( op ){// query
qans = 0;
while( head[a] != head[b] ){
if( depth[head[a]] > depth[head[b]] ){
qans = max( qans, query( aintp[head[a]], aintp[a] ) );
a = par[head[a]];
}else{
qans = max( qans, query( aintp[head[b]], aintp[b] ) );
b = par[head[b]];
}
}
qans = max( qans, query( aintp[a], aintp[b] ) );
fprintf( fout, "%d\n", qans );
}else{
b++;
val[a] = b;
update( aintp[a], b );
}
}
fclose( fin );
fclose( fout );
return 0;
}