#include <iostream>
#include <stdio.h>
#include <vector>
#include <iterator>
using namespace std;
#define NMAX 100005
#define logNMAX 20
#define MIN(x,y) (niv[x] < niv[y]) ? x : y
#define compute(x,y) (v[x] > v[y]) ? x : y
int N, M, K, L, i, j, k, v[NMAX], weight[NMAX], niv[NMAX], pos[NMAX], lg[2*NMAX], ET[logNMAX][2*NMAX], posINlant[NMAX], nrlant[NMAX];
int tatal[NMAX]; /// radacina lantului
int *stlant[NMAX];
vector<int>muchie[NMAX], lant[NMAX];
int DFS1(int xp,int h)
{
int wxp, imw, mw, w, ok, l; /// wxp weight xp, imw index max weight, mx max weight, w of sons, ok marcheaza frunza, l lant xp
wxp = imw = mw = w = ok = 0;
ET[0][++K] = xp;
pos[xp] = K;
niv[xp] = h;
for(vector<int>::iterator it = muchie[xp].begin() ; it != muchie[xp].end() ; ++it)
if( niv[*it] == 0 )
{
ok = 1;
w = DFS1(*it,h+1);
wxp += w + 1;
ET[0][++K] = xp; /// introduc xp in parcurgerea euleriana dupa fiecare fiu
tatal[nrlant[*it]] = xp; /// radacina lanturilor fiilor este xp
if( mw <= w ) /// sa stiu pe care lant al fiilor il aleg
{
imw = *it;
mw = w;
}
}
if( ok == 0 ) /// creez un lant nou in frunze
l = ++L;
else
l = nrlant[imw];
nrlant[xp] = l;
lant[l].push_back(xp);
posINlant[xp] = lant[l].size();
return wxp;
}
void RMQ_build()
{
lg[1] = 0;
for(i = 2 ; i <= K ; ++i)
lg[i] = lg[i/2] + 1;
for(i = 1 ; i <= lg[K] ; ++i)
for(j = 1 ; j <= K ; ++j)
ET[i][j] = MIN( ET[i-1][j] , ET[i-1][j+(1<<(i-1))] );
}
int lca(int x, int y)
{
int p1,p2,l;
p1 = min(pos[x], pos[y]);
p2 = max(pos[x], pos[y]);
l = lg[p2-p1+1];
return MIN( ET[l][p1] , ET[l][p2-(1<<l)+1] );
}
void ST_build()
{
for(i = 1 ; i <= N ; ++i)
posINlant[i] = lant[nrlant[i]].size() - posINlant[i] + 1; /// atribui pozitia corecta in lant de sus in jos
for(i = 1 ; i <= L ; ++i)
{
int n = lant[i].size();
stlant[i] = new int[2*n+5]; /// +5 sa nu iasa din memorie
for(k = 0 ; k < 2*n ; ++k)
stlant[i][k] = 0;
for(vector<int>::iterator it = lant[i].begin() ; it != lant[i].end() ; ++it)
stlant[i][n+( posINlant[*it]-1 )] = *it;
for(k = n-1 ; k > 0 ; --k)
stlant[i][k] = compute(stlant[i][k*2] , stlant[i][k*2+1]);
}
}
void ST_modify(int xp,int val)
{
int n,l,p;
v[xp] = val;
l = nrlant[xp];
n = lant[l].size();
p = posINlant[xp];
for(p += n-1 ; p > 0 ; p >>= 1)
stlant[l][p>>1] = compute(stlant[l][p] , stlant[l][p^1]);
}
int ST_query(int p1, int p2, int l , int n)
{
int left, right, sol = 0; v[sol] = 0;
left = min(p1 , p2);
right= max(p1 , p2);
for(left += n-1, right += n-1 ; left <= right ; left >>= 1 , right >>= 1)
{
if( left % 2 == 1 ) { sol = compute(sol, stlant[l][left]); left++; }
if(right % 2 == 0 ) { sol = compute(sol, stlant[l][right]); right--; }
}
return sol;
}
int lant_sol(int x,int lcaxy)
{
int sol = 0;
while( true )
{
if( nrlant[x] == nrlant[lcaxy] )
{
sol = compute(sol , ST_query(posINlant[x], posINlant[lcaxy], nrlant[x], lant[nrlant[x]].size()) );
break;
}
else
{
sol = compute(sol , ST_query(posINlant[x], 1, nrlant[x], lant[nrlant[x]].size()) );
x = tatal[nrlant[x]];
}
}
return sol;
}
int ValMaxHPD(int x, int y)
{
int lcaxy = lca(x,y);
return v[ compute(lant_sol(x,lcaxy) , lant_sol(y,lcaxy)) ];
}
int main()
{
int q, x, y, rad;
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
scanf("%d %d", &N, &M);
for(i = 0 ; i < N ; ++i)
scanf("%d",&v[i+1]);
for(i = 1 ; i < N ; ++i)
{
scanf("%d %d", &x, &y);
muchie[x].push_back(y);
muchie[y].push_back(x);
}
rad = 1;
K = 0; L = 0;
DFS1(rad,1); tatal[nrlant[rad]] = 0; RMQ_build(); ST_build();
for(i = 0 ; i < M ; ++i)
{
scanf("%d %d %d", &q, &x, &y);
if( q == 0 )
ST_modify(x,y);
else
printf("%d\n", ValMaxHPD(x,y));
}
return 0;
}