#include <cstdio>
#include <iostream>
#include<vector>
using namespace std;
const int NMAX = 25;
typedef vector<int> vi ;
typedef pair<int,int> p;
#define sd second
#define pb push_back
p vertex[NMAX];
vi edges[NMAX];
int maximum[NMAX];
int depth[NMAX];
int grad[NMAX];
int str[NMAX][NMAX];
int rad[NMAX] , poz[NMAX];
int father[NMAX];
int value[NMAX];
int tot;
int viz[NMAX];
void dfs(int nod)
{
for(auto it : edges[nod])
{
if(!viz[it])
viz[it]=nod,grad[it]=grad[nod]+1,dfs(it);
if(it!=viz[nod])
vertex[nod].sd += vertex[it].sd;
}
vertex[nod].sd++;
bool ok = 0;
for(auto it : edges[nod])
if(it!=viz[nod]&&vertex[it].sd >= (vertex[nod].sd + 1)/2)
{
vertex[nod].first=vertex[it].first;
str[vertex[it].first][++str[vertex[it].first][0]]=value[nod];
depth[nod]=depth[it]+1;
maximum[vertex[nod].first]=max(maximum[vertex[nod].first], value[nod]);
ok = 1;
break;
}
if(!ok)
{
vertex[nod].first=++tot;
str[tot][++str[tot][0]]=value[nod];
depth[nod]=1;
maximum[vertex[nod].first]=max(maximum[vertex[nod].first], value[nod]);
}
}
void dfs1(int nod)
{
for(auto it:edges[nod])
{
if(it!=viz[nod])
{
if(vertex[it].first!=vertex[nod].first)
father[vertex[it].first] = vertex[nod].first , rad[vertex[it].first]=depth[nod] ;
dfs1(it);
}
}
}
/// clique maxima;
int aint[NMAX][4*NMAX];
void build(int st , int dr , int nod, int k)
{
if(st == dr)
aint[k][nod]=str[k][st];
else
{
int med=(st + dr)>>1;
build(st,med,2*nod,k);
build(med+1,dr,2*nod+1,k);
aint[k][nod]=max(aint[k][2*nod],aint[k][2*nod+1]);
}
}
/*
void update(int st,int dr,int nod, int poz , int val, int k)
{
if(st == dr)aint[k][nod]=val;
else
{
int med=(st+dr)>>1;
if(poz<=med)update(st,med,2*nod,poz,val,k);
else
update(med+1,dr,2*nod+1,poz,val,k);
aint[k][nod]=max(aint[k][2*nod],aint[k][2*nod+1]);
}
}*/
int query(int st, int dr, int nod, int l, int r ,int k)
{
if(l <= st && dr <=r)
return aint[k][nod];
else
{
int med =(st + dr)/2;
int a = 0 , b = 0;
if(l<=med)
a = query(st , med,2*nod , l , r, k);
if(r>med)
b = query(med+1 , dr , 2*nod+1, l , r , k);
return max(a,b);
}
}
int lca(int a ,int b)
{
if(a == b)return a;
if(grad[a] > grad[b])swap(a,b);
if(viz[b]!=a)
return lca(a ,viz[b]);
}
int fct (int a , int b)
{
int val_max = 0 ;
if(grad[a] > grad[b])swap(a,b);
int x1 = vertex[a].first , x2 = vertex[b].first;
if(x1 == x2)
return query(1,str[x1][0],1 ,min(depth[a],depth[b]),max(depth[a],depth[b]) ,x1);
else
{
int x3 = father[x2];
int ant = x2;
while(x3!=x1)
{
ant = x3;
val_max=max(val_max,maximum[x3]);
x3 = father[x3];
}
int sol = query(1,str[x1][0],1,rad[ant],depth[a],x1);
int sol1= query(1,str[x2][0],1,depth[b],str[x2][0],x2);
val_max=max(val_max,max(sol,sol1));
return val_max;
}
}
int main()
{
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
int n, q, i, j, a, b , val_max=0;
cin >> n >> q;
for(i = 1; i<=n; i++)
scanf("%d",&value[i]);
for(i=1; i<n; ++i)
{
scanf("%d%d",&a,&b);
edges[a].pb(b);
edges[b].pb(a);
}
grad[1]=1 , viz[1] = 1;
dfs(1);
dfs1(1);
for(i = 1 ; i<=tot;++i)
build(1 ,str[i][0] ,1 , i);
int op;
for(i = 1 ; i <= q; ++i)
{
cin >> op >> a >> b;
if(op == 0)
{
continue;
int x1 = vertex[a].first;
//update(1,str[x1][0] , 1 , depth[a] , b , x1);
continue;
}
int lca1=lca(a,b);
int sol1=fct(a,lca1),sol2=fct(b,lca1);
cout<<max(sol1,sol2)<<endl;
}
return 0;
}