#include<bits/stdc++.h>
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
int n,m,cost[100005],niv[100005],dim[100005],head[100005],aint[4*100005],label[100005],k=0,poz[100005],dad[100005];
vector<int>v[100005];
//label[i]=numerotam nodurile astfel incat cele grele sa fie primele
void dfs(int nod, int tata)
{
dad[nod]=tata;
dim[nod]=1;
for(auto it:v[nod])
{
if(it!=tata)
{
niv[it]=niv[nod]+1;
dfs(it,nod);
dim[nod]+=dim[it];
}
}
}
void dfs_heavy(int nod, int tata)
{
label[++k]=nod;
poz[nod]=k;
int maxi=-1,val=0;
for(auto it:v[nod])
if(it!=tata && dim[it]>maxi)
maxi=dim[it],val=it;
if(val==0)
return;
head[val]=head[nod];
dfs_heavy(val,nod);
for(auto it:v[nod])
if(it!=val && it!=tata)
dfs_heavy(it,nod);
}
void update(int nod, int st, int dr, int poz1, int val)
{
if(st==dr)
aint[nod]=val;
else
{
int mij=(st+dr)/2;
if(poz1<=mij)
update(2*nod,st,mij,poz1,val);
else
update(2*nod+1,mij+1,dr,poz1,val);
aint[nod]=max(aint[2*nod],aint[2*nod+1]);
}
}
int query(int nod, int st, int dr, int l, int r)
{
if(st==l && dr==r)
return aint[nod];
else
{
int mij=(st+dr)/2;
if(r<=mij)
return query(2*nod,st,mij,l,r);
else
if(l>=mij+1)
return query(2*nod+1,mij+1,dr,l,r);
else
return max(query(2*nod,st,mij,l,mij),query(2*nod+1,mij+1,dr,mij+1,r));
}
}
int query_heavy(int x ,int y)
{
int sol;
if(head[x]==head[y])
{
if(niv[x]>niv[y])
swap(x,y);
sol=query(1,1,n,poz[x],poz[y]);
}
else
{
if(niv[head[x]]<niv[head[y]])
swap(x,y);
sol=query(1,1,n,poz[head[x]],poz[x]);
x=dad[head[x]];
sol=max(sol,query_heavy(x,y));
}
return sol;
}
signed main()
{
int i,x,y,type;
f>>n>>m;
for(i=1;i<=n;i++)
f>>cost[i];
for(i=1;i<n;i++)
{
f>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1,0);
for(i=1;i<=n;i++)
head[i]=i;
dfs_heavy(1,0);
for(i=1;i<=n;i++)
update(1,1,n,poz[i],cost[i]);
for(i=1;i<=m;i++)
{
f>>type>>x>>y;
if(type==0)
update(1,1,n,poz[x],y);
else
g<<query_heavy(x,y)<<'\n';
}
return 0;
}