#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
#define f first
#define s second
int W[100010],use[100010],father[100010],tag[100010],pos[100010],i,j,n,nivel[100010],first[100010],x,y,m,nrLanturi,r,v[100010],t;
int a[100010],b[100010],k,ANS;
vector< pair<int,int> > G[100010];
vector< int > lant[100010];
struct SegTree
{
int n,*v,ans;
SegTree( int siz )
{
n = siz;
v = new int[ 4 * n ];
memset( v , 0 , sizeof( v ) );
}
void UPD( int nod, int left, int right, int poz, int val )
{
int middle = ( left + right ) / 2;
if( left == right )
{
v[ nod ] = val;
return;
}
if( poz <= middle )
UPD( 2 * nod , left , middle , poz , val );
else
UPD( 2 * nod + 1 , middle + 1 , right , poz , val );
v[ nod ] = max( v[ 2 * nod ] , v[ 2 * nod + 1 ] );
}
void Update( int poz, int val )
{
UPD( 1 , 1 , n , poz , val );
}
int QR( int nod, int left, int right, int L, int R )
{
int middle = ( left + right ) / 2;
if( left > R || right < L )
return 0;
if( L <= left && right <= R )
return v[ nod ];
return max( QR( 2 * nod , left , middle , L , R ) ,
QR( 2 * nod + 1 , middle + 1 , right , L , R ) );
}
int Query( int L, int R )
{
return QR( 1 , 1 , n , L , R );
}
}*arb[ 100010 ];
void DF1( int nod , int ftr )
{
use[ nod ] = 1;
W[ nod ] = 1;
father[ nod ] = ftr;
nivel[ nod ] = nivel[ ftr ] + 1;
for( int i = 0 ; i < G[ nod ].size() ; i++ )
{
if( !use[ G[ nod ][ i ].s ] )
{
DF1( G[ nod ][ i ].s , nod );
W[ nod ] += W[ G[ nod ][ i ].s ];
G[ nod ][ i ].f = W[ G[ nod ][ i ].s ];
}
}
sort( G[ nod ].begin() , G[ nod ].end() );
}
void DF2( int nod )
{
lant[ nrLanturi ].push_back( nod );
tag[ nod ] = nrLanturi;
pos[ nod ] = lant[ nrLanturi ].size() - 1;
first[ nrLanturi ] = lant[ nrLanturi ][ 1 ];
if( G[ nod ].size() == 1 && nod != 1 )
{
arb[ nrLanturi ] = new SegTree( pos[ nod ] );
for( auto it : lant[ nrLanturi ] )
(*arb[ nrLanturi ]).Update( pos[ it ] , v[ it ] );
nrLanturi++;
lant[ nrLanturi ].push_back( 0 );
}
for( int i = G[ nod ].size() - 1 ; i >= 0 ; i-- )
{
if( G[ nod ][ i ].s == father[ nod ] )
continue;
DF2( G[ nod ][ i ].s );
}
}
void drum( int nod, int a[] )
{
if( tag[ nod ] == 0 )
return;
drum( father[ first[ tag[ nod ] ] ] , a );
a[ ++a[ 0 ] ] = nod;
}
void solve( int nod )
{
if( nivel[ nod ] < nivel[ k ] )
return;
if( nivel[ first[ tag[ nod ] ] ] >= nivel[ k ] )
ANS = max( ANS , (*arb[ tag[ nod ] ]).Query( 1 , pos[ nod ] ) );
else if( nivel[ first[ tag[ nod ] ] ] < nivel[ k ] )
ANS = max( ANS , (*arb[ tag[ nod ] ]).Query( pos[ k ] , pos[ nod ] ) );
solve( father[ first[ tag[ nod ] ] ] );
}
int main()
{
lant[ 1 ].push_back( 0 );
nrLanturi = 1;
fin>>n>>m;
for( i = 1 ; i <= n ; i++ )
{
fin>>v[ i ];
}
for( i = 1 ; i < n ; i++ )
{
fin>>x>>y;
G[ x ].push_back( {0,y});
G[ y ].push_back( {0,x});
}
DF1( 1 , 0 );
DF2( 1 );
for( i = 1 ; i <= m ; i++ )
{
fin>>t>>x>>y;
if( t == 0 )
{
(*arb[ tag[ x ] ]).Update( pos[ x ] , y );
}
else
{
a[ 0 ] = 0;
drum( x , a );
b[ 0 ] = 0;
drum( y , b );
for( j = 1 ; j <= min( a[ 0 ] , b[ 0 ] ) ; j++ )
{
if( j == min( a[ 0 ] , b[ 0 ] ) )
break;
if( a[ j ] != b[ j ] )
break;
}
if( nivel[ a[ j ] ] < nivel[ b[ j ] ] )
k = a[ j ];
else
k = b[ j ];
ANS = 0;
solve( x );
solve( y );
fout<<ANS<<'\n';
}
}
return 0;
}