#include <fstream>
#include <vector>
#define LS nod<<1
#define RS (nod<<1)+1
#define MID ((l+r)>>1)
#define GR(x,y) GetRange(x,y,1,1,n)
using namespace std;
int n,m,val[100005],aint[400005],level[100005],weight[100005],lant[100005],tt[100005],nl,pos[100005],vpos,aibase[100005];
bool viz[100005];
vector<int> g[100005],chain[100005];
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
void dfs(int nod)
{
viz[nod]=1;
weight[nod]=1;
int maxw=0;
for(size_t i=0;i<g[nod].size();++i)
{
int vecin=g[nod][i];
if(viz[vecin])
continue;
tt[vecin]=nod;
level[vecin]=level[nod]+1;
dfs(vecin);
if(weight[vecin]>weight[maxw])
maxw=vecin;
weight[nod]+=weight[vecin];
}
if(maxw)
lant[nod]=lant[maxw];
else
lant[nod]=++nl;
chain[lant[nod]].push_back(nod);
}
void Build(int nod,int l,int r)
{
if(l==r)
{
aint[nod]=val[aibase[l]];
return;
}
Build(LS,l,MID);
Build(RS,MID+1,r);
aint[nod]=max(aint[LS],aint[RS]);
}
void Update(int x,int val,int nod,int l,int r)
{
if(l==r)
{
aint[nod]=val;
return;
}
if(x>MID)
Update(x,val,RS,MID+1,r);
else
Update(x,val,LS,l,MID);
aint[nod]=max(aint[LS],aint[RS]);
}
inline int TataLant(int x)
{
return tt[chain[x].back()];
}
int GetRange(int x,int y,int nod,int l,int r)
{
if(r<x || l>y)
return 0;
if(l>=x && r<=y)
return aint[nod];
return max(GetRange(x,y,LS,l,MID),GetRange(x,y,RS,MID+1,r));
}
int Query(int x,int y)
{
int vmx=0;
while(lant[x]!=lant[y])
{
int ttx=TataLant(lant[x]),tty=TataLant(lant[y]);
if(level[ttx]>level[tty])
{
vmx=max(vmx,GR(pos[x],pos[chain[lant[x]].back()]));
x=ttx;
}
else
{
vmx=max(vmx,GR(pos[y],pos[chain[lant[y]].back()]));
y=tty;
}
}
if(pos[x]>pos[y])
swap(x,y);
return max(vmx,GR(pos[x],pos[y]));
}
int main()
{
int i,x,y;
fin>>n>>m;
for(i=1;i<=n;++i)
fin>>val[i];
for(i=1;i<n;++i)
{
fin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
level[1]=1;
dfs(1);
for(i=1;i<=nl;++i)
for(size_t j=0;j<chain[i].size();++j)
aibase[pos[chain[i][j]]=++vpos]=chain[i][j];
Build(1,1,n);
while(m--)
{
fin>>i>>x>>y;
if(i)
fout<<Query(x,y)<<"\n";
else
Update(pos[x],y,1,1,n);
}
return 0;
}