#include <bits/stdc++.h>
using namespace std;
ifstream f ("heavypath.in");
ofstream g ("heavypath.out");
const int nmax=1e5+3;
int n,t,x,y,lvl[nmax],sz[nmax],ind[nmax],caz,usu[nmax],k,m,val[nmax],poz[nmax],tir[2*nmax];
vector <int> v[nmax],path[nmax];
void dfs(int nod,int ant)
{
lvl[nod]=lvl[ant]+1;
sz[nod]=1;
int bst=0;
for(int i=0;i<v[nod].size();++i)
{
int urm=v[nod][i];
if(urm==ant) continue;
dfs(urm,nod);
sz[nod]+=sz[urm];
if(sz[urm]>sz[bst]) bst=urm;
}
for(int i=0;i<v[nod].size();++i)
{
int urm=v[nod][i];
if(urm!=ant&&urm!=bst) usu[ind[urm]]=nod;
}
if(!bst) ind[nod]=++k;
else ind[nod]=ind[bst];
path[ind[nod]].push_back(nod);
}
void update(int t,int x)
{
t+=n;
tir[t]=x;
for(;k>1;k>>=1) tir[k>>1]=max(tir[k],tir[k^1]);
}
int gioto(int x,int y)
{
int ans=0;
x+=n;
y+=n;
for(;x<y;x>>=1,y>>=1)
{
if(x&1) ans=max(ans,tir[x++]);
if(y&1) ans=max(ans,tir[--y]);
}
return ans;
}
int querry(int x,int y)
{
int sol=0;
while(ind[x]!=ind[y])
{
if(lvl[usu[ind[x]]]<lvl[usu[ind[y]]]) swap(x,y);
sol=max(sol,gioto(poz[x],poz[path[ind[x]].back()]+1));
x=usu[ind[x]];
}
if(poz[x]>poz[y]) swap(x,y);
return max(sol,gioto(poz[x],poz[y]+1));
}
int main()
{
ios::sync_with_stdio(false);
f>>n>>m;
for(int i=1;i<=n;++i) f>>val[i];
for(int i=1;i<n;++i)
{
f>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1,0);
int nr=0;
for(int i=1;i<=k;++i)
{
for(int j=0;j<path[i].size();++j)
{
int urm=path[i][j];
poz[urm]=++nr;
tir[nr+n]=val[urm];
}
}
for(int i=n;i;--i) tir[i]=max(tir[i<<1],tir[i<<1|1]);
while(m--)
{
f>>caz>>x>>y;
if(!caz) update(poz[x],y);
else g<<querry(x,y)<<'\n';
}
return 0;
}