#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] , Gp[NMAX];
int tp[NMAX] , p[NMAX];
bool u[NMAX];
void read();
void DFS(int nod);
void write();
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);
int 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 = 1 ; i<= N ; ++i )
for(int j = 0 ; j <(int)G[i].size() ; ++j )
if(wp[i] != wp[G[i][j]])
{
Gp[wp[i]].pb(wp[G[i][j]]);
Gp[wp[G[i][j]]].pb(wp[i]);
}
DFSp(wp[1]);
for(int i = 1 ; i<= N ; ++i )
for(int j = 0 ; j < (int)G[i].size() ; ++j )
if(wp[i] != wp[G[i][j]] && niv[i] < niv[G[i][j]])tp[wp[G[i][j]]] = i;
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
printf("%d\n" , solve(x,y));
}
//write();
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 maxx , fiu;
d[nod] = 1;
if(G[nod].size() == 1 && nod != 1)
{
path[++nrp].pb(nod);
wp[nod] = nrp;
}
else
{
for(int i = 0 ; i < (int)G[nod].size() ; ++i)
{
if(G[nod][i] == t[nod])continue;
maxx = 0;
fiu = 0;
t[G[nod][i]] = nod;
niv[G[nod][i]] = niv[nod]+1;
DFS(G[nod][i]);
if(d[G[nod][i]] > maxx)
{
maxx = d[G[nod][i]];
fiu = G[nod][i];
}
}
path[wp[fiu]].pb(nod);
wp[nod] = wp[fiu];
}
}
void write()
{
freopen("heavypath.out" , "w" , stdout );
for(int i = 1 ; i <= nrp ; ++i )
{
for(int j = 0 ; j < A[i].size() ; ++j )
printf("%d " , A[i][j] );
printf("\n");
}
}
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 path , int n , int l , int r , int a , int b)
{
if(a <= l && b >= r)return A[path][n];
else
{
int m = (l+r)/2,maxx = -1;
if(a <= m)
maxx = query(path,2*n,l,m,a,b);
if(b > m)
maxx = max(maxx, query(path , 2*n+1,m+1,r,a,b));
return maxx;
}
}
void DFSp(int nod)
{
u[nod] = 1;
for(int i = 0 ; i <(int)Gp[nod].size() ; ++i )
{
if(u[Gp[nod][i]])continue;
lev[Gp[nod][i]] = lev[nod]+1;
DFSp(Gp[nod][i]);
}
}
int solve(int x , int y)
{
int rez = 0 , aux;
while(wp[x] != wp[y])
{
if(lev[wp[x]] < lev[wp[y]])
{
rez = max(rez,query(wp[y],1,1,path[wp[y]].size()-1,1,p[y]));
y = tp[wp[y]];
}
else
{
rez = max(rez,query(wp[x],1,1,path[wp[x]].size()-1,1,p[x]));
x = tp[wp[x]];
}
}
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]));
return rez;
}