#include <bits/stdc++.h>
#define Dim 100010
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
ifstream lop("aux.in");
ofstream h("aux.out");
int N,M,Val[Dim],Poz[Dim],Roof[Dim],Label[Dim],DX[Dim],A,B;
int cnt=1,cont,Euler[3*Dim],Deep[3*Dim],rmq[18][3*Dim],First[Dim];
int op,lca,Gap[Dim],Tree[4*Dim],numara,ans,Max,LimA,LimB;
bool viz[Dim];
vector <int> Chain[Dim],V[Dim];
void init()
{
for(int i=1;i<=N;i++) viz[i]=0;
}
void DFS_Count(int nod)
{
viz[nod]=1;
for(unsigned int i=0;i<V[nod].size();i++)
{
int vecin=V[nod][i];
if(!viz[vecin])
{
DFS_Count(vecin);
DX[nod]+=DX[vecin];
}
}
}
void Decomposition(int nod,int index)
{
viz[nod]=1;
Chain[cnt].push_back(nod);
Poz[nod]=index;
Label[nod]=cnt;
pair <int,int> which;
for(unsigned int i=0;i<V[nod].size()&&DX[nod]!=1;i++)
{
int vecin=V[nod][i];
if(DX[vecin]>which.second&&!viz[vecin]) which={vecin,DX[vecin]};
if(i==V[nod].size()-1) Decomposition(which.first,index+1);
}
for(unsigned int i=0;i<V[nod].size();i++)
{
int vecin=V[nod][i];
if(!viz[vecin]&&vecin!=which.first)
{
cnt++;
Roof[cnt]=nod;
Decomposition(vecin,1);
}
}
}
void DFS_Oiler(int nod,int level)
{
viz[nod]=1;
Euler[++cont]=nod;
Deep[cont]=level;
First[nod]=cont;
for(unsigned int i=0;i<V[nod].size();i++)
{
int vecin=V[nod][i];
if(!viz[vecin])
{
DFS_Oiler(vecin,level+1);
Euler[++cont]=nod;
Deep[cont]=level;
}
}
}
void RMQ()
{
for(int i=1;i<=cont;i++) rmq[0][i]=i;
for(int i=1;(1<<i)<=cont;i++)
for(int j=1;j+(1<<i)-1<=cont;j++)
{
A=rmq[i-1][j];
B=rmq[i-1][j+(1<<(i-1))];
if(Deep[A]<=Deep[B]) rmq[i][j]=A;
else rmq[i][j]=B;
}
}
int Lowest(int X,int Y)
{
int pozA=First[X];
int pozB=First[Y];
if(pozA>pozB) swap(pozA,pozB);
int dif=log2(pozB-pozA+1);
if(Deep[rmq[dif][pozA]]<=Deep[rmq[dif][pozB-(1<<dif)+1]]) return Euler[rmq[dif][pozA]];
else return Euler[rmq[dif][pozB-(1<<dif)+1]];
}
void Build(int nod,int st,int dr,int lant,int defazaj)
{
if(st==dr)
{
numara++;
Tree[nod+defazaj]=Val[Chain[lant][numara]];
return;
}
int mij=(st+dr)/2;
Build(2*nod,st,mij,lant,defazaj);
Build(2*nod+1,mij+1,dr,lant,defazaj);
Tree[nod+defazaj]=max(Tree[2*nod+defazaj],Tree[2*nod+1+defazaj]);
}
void Update(int nod,int st,int dr,int lant,int defazaj)
{
if(st==dr)
{
Tree[nod+defazaj]=B;
return;
}
int mij=(st+dr)/2;
if(Poz[A]<=mij)
Update(2*nod,st,mij,lant,defazaj);
if(Poz[A]>=mij+1)
Update(2*nod+1,mij+1,dr,lant,defazaj);
Tree[nod+defazaj]=max(Tree[2*nod+defazaj],Tree[2*nod+1+defazaj]);
}
void Query(int nod,int st,int dr,int lant,int defazaj)
{
if(st>=LimA&&dr<=LimB)
{
Max=max(Max,Tree[nod+defazaj]);
return;
}
int mij=(st+dr)/2;
if(LimA<=mij)
Query(2*nod,st,mij,lant,defazaj);
if(LimB>=mij+1)
Query(2*nod+1,mij+1,dr,lant,defazaj);
}
void Recursion(int X,int Y)
{
if(Label[X]==Label[Y])
{
LimA=Poz[X]; LimB=Poz[Y];
Max=0;
Query(1,1,Chain[Label[X]].size(),Label[X],Gap[Label[X]]);
ans=max(ans,Max);
return;
}
else
{
LimA=1; LimB=Poz[Y];
Max=0;
Query(1,1,Chain[Label[Y]].size(),Label[Y],Gap[Label[Y]]);
ans=max(ans,Max);
Recursion(X,Roof[Label[Y]]);
}
}
int main()
{
f>>N>>M;
for(int i=1;i<=N;i++)
{
f>>Val[i];
DX[i]=1;
}
for(int i=1;i<N;i++)
{
f>>A>>B;
V[A].push_back(B);
V[B].push_back(A);
}
DFS_Count(1); init();
Decomposition(1,1); init();
/*for(int i=1;i<=cnt;i++)
{
cout<<Roof[i]<<'\n';
for(unsigned int j=0;j<Chain[i].size();j++) cout<<Chain[i][j]<<" "<<Poz[Chain[i][j]]<<'\n';
cout<<'\n'<<'\n';
}*/
DFS_Oiler(1,1); init();
RMQ();
for(int i=1;i<=cnt;i++)
{
numara=-1;
if(i>1) Gap[i]=Gap[i-1]+4*Chain[i-1].size();
Build(1,1,Chain[i].size(),i,Gap[i]);
}
for(int i=1;i<=M;i++)
{
f>>op>>A>>B;
if(!op)
{
Update(1,1,Chain[Label[A]].size(),Label[A],Gap[Label[A]]);
}
else
{
lca=Lowest(A,B);
ans=0;
Recursion(lca,A);
Recursion(lca,B);
g<<ans<<'\n';
}
}
return 0;
}