#include <bits/stdc++.h>
#define pb push_back
#define N 100005
using namespace std;
int gr[N],Tata[N],fg,niv[N],lant[N],cnt,poz[N],i,A[N],m,fs,y,x,a,b,sol,n,nn,t;
vector<int>v[N],p[N],arb[N];
void df(int nod,int tata)
{
gr[nod]=1;
int fg=0;
for(auto fiu:v[nod])
{
if(fiu==tata)
continue;
Tata[fiu]=nod;
niv[fiu]=niv[nod]+1;
df(fiu,nod);
gr[nod]+=gr[fiu];
if(gr[fg]<gr[fiu])
fg=fiu;
}
if(v[nod].size()==1&&nod!=1)
{
lant[nod]=++cnt;
p[cnt].pb(0);
p[cnt].pb(nod);
poz[nod]=1;
return;
}
lant[nod]=lant[fg];
p[lant[nod]].pb(nod);
poz[nod]=p[lant[nod]].size()-1;
}
void build(int nod,int l,int r)
{
int m,fs;
if(l==r)
{
arb[i][nod]=A[p[i][l]];
return;
}
m=(l+r)/2;
fs=2*nod;
build(fs,l,m);
build(fs+1,m+1,r);
arb[i][nod]=max(arb[i][fs],arb[i][fs+1]);
}
void update(int nod,int l,int r)
{
int m,fs;
if(l==r)
{
arb[lant[x]][nod]=y;
return;
}
m=(l+r)/2;
fs=2*nod;
if(poz[x]<=m)
update(fs,l,m);
else
update(fs+1,m+1,r);
arb[lant[x]][nod]=max(arb[lant[x]][fs],arb[lant[x]][fs+1]);
}
void query(int nod,int l,int r)
{
int m,fs;
if(a<=l&&r<=b)
{
sol=max(sol,arb[lant[x]][nod]);
return;
}
if(a>r||b<l)
return;
m=(l+r)/2;
fs=2*nod;
query(fs,l,m);
query(fs+1,m+1,r);
}
int main()
{
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&A[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].pb(y);
v[y].pb(x);
}
niv[1]=1;
df(1,0);
for(i=1;i<=cnt;i++)
{
reverse(p[i].begin()+1,p[i].end());
nn=p[i].size();
arb[i].resize(4*nn+10);
build(1,1,nn-1);
}
for(i=1;i<=n;i++)
poz[i]=p[lant[i]].size()-poz[i];
for(;m;m--)
{
scanf("%d%d%d",&t,&x,&y);
if(t==0)
update(1,1,p[lant[x]].size()-1);
else
{
sol=0;
for(;;)
{
if(lant[x]==lant[y])
{
a=min(poz[x],poz[y]);
b=max(poz[x],poz[y]);
query(1,1,p[lant[x]].size()-1);
printf("%d\n",sol);
break;
}
if(niv[p[lant[x]][1]]<niv[p[lant[y]][1]])
swap(x,y);
a=1;
b=poz[x];
query(1,1,p[lant[x]].size()-1);
x=Tata[p[lant[x]][1]];
}
}
}
return 0;
}