#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
using namespace std;
int n,m,p[100001],poz[100001],nrfii[100001],t,v[100001],T[100001],nr[100001],f[100001],niv[100001],pniv[100001];
int *aint[100001];
bool o[100001];
//p - in ce lant se afla fiecare nod
//poz - pe ce pozitie in lant
vector<int> G[100001],path[100001],Gp[100001];
void citire()
{
int i,x,y;
scanf("%i%i",&n,&m);
for (i=1;i<=n;i++) scanf("%i",&v[i]);
for (i=1;i<n;i++)
{
scanf("%i%i",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
}
void DFS(int s)
{
int i,z=G[s].size(),m=0;
nrfii[s]=1;
for (i=0;i<z;i++)
if (!nrfii[G[s][i]])
{
T[G[s][i]]=s;
niv[G[s][i]]=niv[s]+1;
DFS(G[s][i]);
nrfii[s]+=nrfii[G[s][i]];
if (nrfii[G[s][i]]>nrfii[m]) m=G[s][i];
}
if (z==1&&s!=1) //e frunza - creez un nou lant
{
path[++t].push_back(s);
p[s]=t;
}
else
{
path[p[m]].push_back(s);
p[s]=p[m];
for (i=0;i<z;i++)
if (p[s]!=p[G[s][i]])
Gp[p[s]].push_back(p[G[s][i]]);
}
}
void DFSp(int s)
{
int z=Gp[s].size();
o[s]=1;
for (int i=0;i<z;i++)
if (!o[Gp[s][i]])
{
pniv[Gp[s][i]]=pniv[s]+1;
DFSp(Gp[s][i]);
}
}
void buildAint(int k,int a,int b,int l)
{
if (a==b)
{
aint[l][k]=v[path[l][a-1]];
f[path[l][a-1]]=k;
poz[path[l][a-1]]=a;
}
else
{
int m=(a+b)>>1,h=k<<1;
buildAint(h,a,m,l);
buildAint(h+1,m+1,b,l);
aint[l][k]=max(aint[l][h],aint[l][h+1]);
}
}
void splitTree()
{
int i;
DFS(1);
for (i=1;i<=t;i++)
{
reverse(path[i].begin(),path[i].end()); //sortez lantul dupa nivel
nr[i]=path[i].size();
aint[i]=(int*) calloc(4*nr[i]+1,sizeof(int));
buildAint(1,1,nr[i],i);
}
}
void update(int i,int k)
{
if (k)
{
int h=k<<1;
aint[i][k]=max(aint[i][h],aint[i][h+1]);
update(i,k>>1);
}
}
int det(int k,int x,int y,int a,int b,int l)
{
if (x>=a&&y<=b) return aint[l][k];
else
{
int m=(x+y)>>1,r=0,h=k<<1;
if (m>=a) r=max(r,det(h,x,m,a,b,l));
if (m<b) r=max(r,det(h+1,m+1,y,a,b,l));
return r;
}
}
int query(int x,int y)
{
int r=v[x];
while (x!=y)
if (p[x]==p[y])
{
if (niv[x]>niv[y]) swap(x,y);
r=max(r,det(1,1,nr[p[x]],poz[x],poz[y],p[x]));
y=x;
}
else
{
if (pniv[p[x]]>pniv[p[y]]) swap(x,y);
r=max(r,det(1,1,nr[p[y]],1,poz[y],p[y]));
y=T[path[p[y]][0]];
}
return r;
}
void solve()
{
int q,x,y;
while (m--)
{
scanf("%i%i%i",&q,&x,&y);
if (q==0)
{
aint[p[x]][f[x]]=y;
v[x]=y;
update(p[x],f[x]>>1);
}
else printf("%i\n",query(x,y));
}
}
int main()
{
freopen ("heavypath.in","r",stdin);
freopen ("heavypath.out","w",stdout);
citire();
splitTree(); //descompun arborele in lanturi
DFSp(p[1]);
solve();
fclose(stdin);
fclose(stdout);
return 0;
}