#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
#define NMAX 100001
#define pb push_back
int N , M , d[NMAX] , t[NMAX] , nrp , wp[NMAX] , v[NMAX] ,niv[NMAX] , lev[NMAX] ;
vector<int> G[NMAX] , path[NMAX] , A[NMAX];
int tp[NMAX] , p[NMAX];
bool u[NMAX];
void read();
void DFS(int nod);
void build(int path , int n , int l , int r);
void update(int path , int n , int l , int r , int poz , int nod);
int query(int path , int n , int l , int r , int a , int b);
void solve(int x , int y);
void DFSp(int nod);
int main()
{
int tip, x , y;
read();
DFS(1);
for(int i = 1 ; i <= nrp ; ++i )
{
path[i].pb(0);
reverse(path[i].begin(),path[i].end());
A[i].resize(path[i].size()*4);
build(i,1,1,path[i].size()-1);
for(int j = 1 ; j <(int)path[i].size() ; ++j )
p[path[i][j]] = j;
}
for(int i = 2 ; i<= N ; ++i )
if(wp[i] != wp[t[i]])tp[wp[i]] = t[i];
DFSp(1);
for(int i = 1 ; i<= M; ++i )
{
scanf("%d%d%d" , &tip , &x , &y );
if(!tip)
{
v[x] = y;
update(wp[x],1,1,path[wp[x]].size()-1,p[x],x);
}
else
solve(x,y);
}
return 0;
}
void read()
{
int x , y;
freopen("heavypath.in" , "r" , stdin );
freopen("heavypath.out" , "w" , stdout );
scanf("%d%d" , &N , &M );
for(int i = 1 ; i <= N ; ++i )
scanf("%d" , &v[i]);
for(int i = 1 ; i < N ; ++i )
{
scanf("%d%d" , &x , &y );
G[x].pb(y);
G[y].pb(x);
}
}
void DFS(int nod)
{
int fiu = -1;
d[nod] = 1;
for(int i = 0 ; i < (int)G[nod].size() ; ++i)
{
if(G[nod][i] == t[nod])continue;
t[G[nod][i]] = nod;
niv[G[nod][i]] = niv[nod]+1;
DFS(G[nod][i]);
d[nod] += d[G[nod][i]];
if(fiu == -1 || d[G[nod][i]] > d[fiu])
fiu = G[nod][i];
}
if(fiu == -1)wp[nod] = ++nrp;
else wp[nod] = wp[fiu];
path[wp[nod]].pb(nod);
}
void build(int i , int n , int l , int r )
{
if(l == r)A[i][n] = v[path[i][l]];
else
{
int m = (l+r)/2;
build(i,2*n,l,m);
build(i,2*n+1,m+1,r);
A[i][n] = max(A[i][2*n] , A[i][2*n+1]);
}
}
void update(int path , int n , int l , int r , int poz , int nod )
{
if( l == r )A[path][n] = v[nod];
else
{
int m = (l+r)/2;
if(poz <= m)update(path,2*n,l,m,poz,nod);
else update(path,2*n+1,m+1,r,poz,nod);
A[path][n] = max(A[path][2*n] , A[path][2*n+1]);
}
}
int query(int i , int n , int l , int r , int a , int b)
{
if(a <= l && b >= r)return A[i][n];
else
{
int m = (l+r)/2,maxx = -1;
if(a <= m)
maxx = query(i,2*n,l,m,a,b);
if(b > m)
maxx = max(maxx, query(i , 2*n+1,m+1,r,a,b));
return maxx;
}
}
void DFSp(int nod)
{
u[nod] = 1;
for(int i = 0 ; i <(int)G[nod].size() ; ++i )
{
if(u[G[nod][i]])continue;
if(wp[nod] != wp[G[nod][i]]) lev[wp[G[nod][i]]] = lev[wp[nod]] + 1;
DFSp(G[nod][i]);
}
}
void solve(int x , int y)
{
int aux, rez = 0;
while(wp[x] != wp[y])
{
if(lev[wp[x]] > lev[wp[y]]){aux = x;x = y;y = aux;}
rez = max(rez,query(wp[y],1,1,path[wp[y]].size()-1,1,p[y]));
y = tp[wp[y]];
}
if(niv[x] > niv[y]){aux = x;x = y;y = aux;}
rez = max(rez,query(wp[x],1,1,path[wp[x]].size()-1,p[x],p[y]));
printf("%d\n" , rez);
}