#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
#define NMAX 100001
#define INF 2000000001
#define pb push_back
int v[NMAX] , f[NMAX] , lev[NMAX] , what_path[NMAX] , t[NMAX] , d[NMAX] , poz[NMAX];
int N , M , dim , maxim;
vector<int> G[NMAX] , path[NMAX] , AI[NMAX];
bool u[NMAX];
void read();
void DFS(int nod , int l);
bool comp(int a , int b)
{
return lev[a] < lev[b];
}
void update(vector<int> &A , int N , int l , int r , int poz , int val);
void query(vector<int> &A , int N , int l , int r , int a , int b);
int query1(int x , int y);
int main()
{
int x , y, z;
read();
DFS(1,0);
t[1] = 1;
for(int i = 1 ; i<= dim ; ++i ){
sort(path[i].begin() , path[i].end() , comp);
AI[i].resize(4*path[i].size());}
for(int i = 1 ; i<= dim ; ++i )
for(int j = 0 ; j <(int)path[i].size() ; ++j ){
poz[path[i][j]] = j;
update(AI[i],1,0,path[i].size()-1,j,v[path[i][j]]);}
for(int i = 1 ; i<= M ; ++i )
{
scanf("%d%d%d" , &z , &x , &y );
if(z == 0)
{
update(AI[what_path[x]],1,0,path[what_path[x]].size()-1,poz[x],y);
v[x] = y;
}
else printf("%d\n" , query1(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 l)
{
lev[nod] = l;
if(G[nod].size() == 1 && G[nod][0] == t[nod]){
path[++dim].pb(nod);
what_path[nod] = dim;
d[nod] = 1;
}
else
{
int maxx = 0 , fiu;
for(int i = 0 ; i <(int)G[nod].size() ; ++i )
{
if(G[nod][i] == t[nod])continue;
t[G[nod][i]] = nod;
DFS(G[nod][i],l+1);
if(maxx < d[G[nod][i]])
{
maxx = d[G[nod][i]];
fiu = G[nod][i];
}
d[nod] += d[G[nod][i]];
}
d[nod]++;
path[what_path[fiu]].pb(nod);
what_path[nod] = what_path[fiu];
}
}
void update(vector<int> &A , int n , int l , int r , int poz , int val)
{
if(l == r)A[n] = val;
else
{
int m = (l+r)/2;
if(poz <= m)
update(A,2*n,l,m,poz,val);
else
update(A,2*n+1,m+1,r,poz,val);
A[n] = max(A[2*n],A[2*n+1]);
}
}
void query(vector<int> &A , int n , int l , int r , int a , int b)
{
if(a <= l && b >= r)maxim = max(maxim,A[n]);
else
{
int m = (l+r)/2;
if(a <= m)
query(A,2*n,l,m,a,b);
if(b > m)
query(A,2*n+1,m+1,r,a,b);
}
}
int query1(int x , int y)
{
int aux;
int rez = max(v[x],v[y]);
while(x != y )
{
if(lev[x] > lev[y])
{
aux = x;
x = y;
y = aux;
}
if(what_path[x] == what_path[y]){
maxim = 0;
query(AI[what_path[x]],1,0,path[what_path[x]].size()-1,poz[x] , poz[y]);
rez = max(rez,maxim);
x = y;}
else
{
maxim = 0;
query(AI[what_path[y]],1,0,path[what_path[y]].size()-1,0,poz[y]);
rez = max(rez,maxim);
y = t[path[what_path[y]][0]];
}
}
return rez;
}