#include <fstream>
#include <vector>
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
#define N 100005
int val[N],parent[N],chain[N],subtree[N],sizee[N],nr,level[N],position[N],descendant[N];
vector<int> v[N],chains[N],aint[N];
void dfs(int x)
{
level[x]=level[parent[x]]+1;
int maxx=-1;
for(auto i:v[x])
if(i!=parent[x])
{
parent[i]=x;
dfs(i);
subtree[x]+=subtree[i];
if(subtree[i]>maxx)
maxx=subtree[i], descendant[x]=i;
}
}
void dfs2(int x)
{
for(auto i:v[x])
if(i!=parent[x])
{
if(descendant[x]==i)
{
chains[chain[x]].push_back(i);
chain[i]=chain[x];
position[i]=position[x]+1;
}
else
{
chains[++nr].push_back(i);
chain[i]=nr;
}
dfs2(i);
}
}
void update(int ind, int nod, int st, int dr, int poz)
{
if(st>poz||dr<poz)
return;
if(st==dr)
{
aint[ind][nod]=val[chains[ind][poz-1]];
return;
}
int mijl=(st+dr)/2;
update(ind,nod*2,st,mijl,poz);
update(ind,nod*2+1,mijl+1,dr,poz);
aint[ind][nod]=max(aint[ind][nod*2],aint[ind][nod*2+1]);
}
int query(int ind, int nod, int st, int dr, int in, int sf)
{
if(in>dr||sf<st)
return -1;
if(in<=st&&dr<=sf)
return aint[ind][nod];
int mijl=(st+dr)/2;
return max(query(ind,nod*2,st,mijl,in,sf),query(ind,nod*2+1,mijl+1,dr,in,sf));
}
int main()
{
int n,m;
f>>n>>m;
for(int i=1;i<=n;i++)
{
f>>val[i];
subtree[i]=1;
}
for(int i=1;i<n;i++)
{
int a,b;
f>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
chain[1]=++nr;
chains[nr].push_back(1);
dfs(1);
dfs2(1);
for(int i=1;i<=nr;i++)
{
sizee[i]=chains[i].size();
aint[i].resize(4*sizee[i]);
for(int j=0;j<sizee[i];j++)
update(i,1,1,sizee[i],j+1);
}
while(m--)
{
int t,x,y;
f>>t>>x>>y;
if(t==0)
{
val[x]=y;
update(chain[x],1,1,sizee[chain[x]],position[x]+1);
}
else
{
int maxx=-1;
while(chain[x]!=chain[y])
{
if(level[chains[chain[x]][0]]<level[chains[chain[y]][0]])
swap(x,y);
maxx=max(maxx,query(chain[x],1,1,sizee[chain[x]],1,position[x]+1));
x=parent[chains[chain[x]][0]];
}
if(position[x]>position[y])
swap(x,y);
g<<max(maxx,query(chain[x],1,1,sizee[chain[x]],position[x]+1,position[y]+1))<<'\n';
}
}
return 0;
}