#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
const int Nmax = 100001;
class Scanner
{
private:
const int BUF_SIZE = 1 << 21;
char *buffer;
int position = BUF_SIZE;
inline char getChar()
{
if ( position == BUF_SIZE )
{
fread( buffer, 1, BUF_SIZE, stdin );
position = 0;
}
return buffer[ position++ ];
}
public:
Scanner()
{
buffer = new char[BUF_SIZE];
}
int nextInt()
{
int nr = 0;
char c;
do
{
c = getChar();
} while ( !isdigit( c ) );
do
{
nr = nr * 10 + c - '0';
c = getChar();
} while ( isdigit( c ) );
return nr;
}
};
class SegmentTree
{
public:
SegmentTree( const int n, const vector<int> &values )
{
if ( n == 0 ) return;
int sz = 4 * n;
N = n;
Tree = new int[sz];
build( 1, 0, N - 1, values );
}
void update( const int position, const int value )
{
update( 1, 0, N - 1, position, value );
}
int query( const int st, const int dr )
{
return query( 1, 0, N - 1, st, dr );
}
private:
int N;
int *Tree;
int middle( int i, int j )
{
return i + ( j - i ) / 2;
}
inline int Lson( const int nod )
{
return nod * 2;
}
inline int Rson( const int nod )
{
return nod * 2 + 1;
}
inline void update_tree( const int nod )
{
Tree[nod] = max( Tree[ Lson( nod ) ], Tree[ Rson( nod ) ] );
}
void build( int nod, int st, int dr, const vector<int> &values )
{
if ( st == dr )
{
Tree[nod] = values[st];
}
else
{
int m = middle( st, dr );
build( Lson( nod ), st, m, values );
build( Rson( nod ), m + 1, dr, values );
update_tree( nod );
}
}
void update( int nod, int st, int dr, const int position, const int value )
{
if ( st == dr )
{
Tree[nod] = value;
}
else
{
int m = middle( st, dr );
if ( position <= m )
update( Lson( nod ), st, m, position, value );
else
update( Rson( nod ), m + 1, dr, position, value );
update_tree( nod );
}
}
int query( int nod, int st, int dr, int st_query, int dr_query )
{
if ( st_query <= st && dr <= dr_query )
{
return Tree[nod];
}
else
{
int value = -1;
int m = middle( st, dr );
if ( st_query <= m )
value = max( value, query( Lson( nod ), st, m, st_query, dr_query ) );
if ( m < dr_query )
value = max( value, query( Rson( nod ), m + 1, dr, st_query, dr_query ) );
return value;
}
}
};
vector <int> Graph[Nmax];
int value[Nmax];
int size[Nmax], father[Nmax], level[Nmax], path[Nmax], length_path[Nmax];
int pos_in_path[Nmax], start_node[Nmax];
vector <SegmentTree> SegmentTrees;
int Number_Of_Paths;
int N, Q;
void DFS( int nod )
{
int heaviestSon = 0;
size[nod] = 1;
for ( auto son: Graph[nod] )
if ( father[son] == 0 )
{
father[son] = nod;
level[son] = level[nod] + 1;
DFS( son );
size[nod] += size[son];
if ( size[heaviestSon] < size[son] )
heaviestSon = son;
}
if ( heaviestSon == 0 )
path[nod] = Number_Of_Paths++;
else
path[nod] = path[heaviestSon];
pos_in_path[nod] = length_path[ path[nod] ]++;
}
void build_heavy_path_decomposition()
{
father[1] = 1;
level[1] = 0;
DFS( 1 );
for ( int i = 1; i <= N; ++i )
{
pos_in_path[i] = length_path[ path[i] ] - pos_in_path[i] - 1;
if ( pos_in_path[i] == 0 )
start_node[ path[i] ] = i;
}
}
void build_segment_trees()
{
vector < vector<int> > pathValue = vector < vector<int> >( Number_Of_Paths );
for ( int i = 0; i < Number_Of_Paths; ++i )
pathValue[i] = vector<int>( length_path[i] );
for ( int i = 1; i <= N; ++i )
pathValue[ path[i] ][ pos_in_path[i] ] = value[i];
for ( int i = 0; i < Number_Of_Paths; ++i )
SegmentTrees.push_back( SegmentTree( pathValue[i].size(), pathValue[i] ) );
}
int query( int x, int y )
{
if ( level[ start_node[ path[x] ] ] < level[ start_node[ path[y] ] ] )
swap( x, y );
if ( path[x] == path[y] )
return SegmentTrees[ path[x] ].query( min( pos_in_path[x], pos_in_path[y] ), max( pos_in_path[x], pos_in_path[y] ) );
else
return max( SegmentTrees[ path[x] ].query( 0, pos_in_path[x] ), query( father[ start_node[ path[x] ] ], y ) );
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
Scanner scan;
N = scan.nextInt();
Q = scan.nextInt();
for ( int i = 1; i <= N; ++i )
value[i] = scan.nextInt();
for ( int i = 1, a, b; i < N; ++i )
{
a = scan.nextInt();
b = scan.nextInt();
Graph[a].push_back( b );
Graph[b].push_back( a );
}
build_heavy_path_decomposition();
build_segment_trees();
for ( int i = 1, tip, a, b; i <= Q; ++i )
{
tip = scan.nextInt();
a = scan.nextInt();
b = scan.nextInt();
if ( tip == 0 )
{
value[a] = b;
SegmentTrees[ path[a] ].update( pos_in_path[a], b );
}
else
{
printf("%d\n", query( a, b ));
}
}
return 0;
}