#include<fstream>
#include<vector>
#include<algorithm>
#define NMAX 100005
#define VEC G[nod][i]
#define son (nod<<1)
#define middle ((left+right)>>1)
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
vector<int> G[NMAX];
int level[NMAX],str[18][NMAX],what[NMAX],lant[NMAX],under[NMAX];
int AINT[(1<<18)],Maxx,start[NMAX],K;
int n,Q,v[NMAX],k,TT[NMAX];
void read()
{
fin>>n>>Q;
for(int i=1;i<=n;i++)
fin>>v[i];
for(int i=1,x,y;i<n;i++)
{
fin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
}
void DFS(int nod,int tt)
{
str[0][nod]=tt;
level[nod]=level[tt]+1;
for(size_t i=0;i<G[nod].size();i++)
if(VEC!=tt)
{
DFS(VEC,nod);
under[nod]+=under[VEC]+1;
}
if(G[nod].size()==1 && nod!=1)
{
lant[nod]=++k;
return;
}
int ind=0,maxim=-1;
for(size_t i=0;i<G[nod].size();i++)
if(VEC!=tt && maxim<under[VEC])
{
maxim=under[VEC];
ind=VEC;
}
lant[nod]=lant[ind];
}
inline void update(int left,int right,int nod,int val,int poz)
{
if(left==right)
{
AINT[nod]=val;
return;
}
if(poz<=middle)
update(left,middle,son,val,poz);
else
update(middle+1,right,son+1,val,poz);
AINT[nod]=max(AINT[son],AINT[son+1]);
}
void query(int left,int right,int nod,int L,int R)
{
if(left>R || right<L)
return;
if(L<=left && right<=R)
{
Maxx=max(Maxx,AINT[nod]);
return;
}
query(left,middle,son,L,R);
query(middle+1,right,son+1,L,R);
}
bool cmp(const int a,const int b)
{
if(lant[a]==lant[b])
return level[a]<level[b];
return lant[a]<lant[b];
}
void group_init()
{
int nods[NMAX];
for(int i=1;i<=n;i++)
nods[i]=i;
sort(nods+1,nods+n+1,cmp);
for(int i=1,L=1,ant=0;i<=n;i++)
{
if(!lant[nods[i]])
continue;
if(lant[nods[i]]!=ant)
{
ant=lant[nods[i]];
start[lant[nods[i]]]=L;
TT[lant[nods[i]]]=i;
}
what[nods[i]]=L;
update(1,n,1,v[nods[i]],L);
L++;
}
}
void ancestors()
{
for(int i=1;(1<<i)<=n;i++)
for(int j=1;j<=n;j++)
str[i][j]=str[i-1][str[i-1][j]];
}
void prep()
{
DFS(1,0);
group_init();
ancestors();
}
void jump(int &x,int &y)
{
int d=level[x]-level[y];
for(int step=17,p=(1<<17);step>=0;step--,p>>=1)
if(d>=p)
{
d-=p;
x=str[step][x];
}
}
int LCA(int x,int y)
{
if(level[x]>level[y])
jump(x,y);
if(level[x]<level[y])
jump(y,x);
if(x==y)
return x;
for(int step=17;step>=0;step--)
if(str[step][x]!=str[step][y])
{
x=str[step][x];
y=str[step][y];
}
return str[0][x];
}
void val(int &x,int lca,int &sol)
{
while(x!=lca)
{
if(lant[x])
{
Maxx=0;
if(lant[x]==lant[lca])
{
query(1,n,1,what[lca],what[x]);
sol=max(sol,Maxx);
break;
}
query(1,n,1,start[lant[x]],what[x]);
sol=max(sol,Maxx);
x=str[0][TT[lant[x]]];
}
else
{
sol=max(sol,v[x]);
x=str[0][x];
}
}
sol=max(sol,v[lca]);
}
int main()
{
read();
prep();
for(int op,x,y,lca,sol;Q;Q--)
{
fin>>op>>x>>y;
if(!op)
{
v[x]=y;
if(lant[x])
update(1,n,1,y,what[x]);
continue;
}
sol=0;
lca=LCA(x,y);
val(x,lca,sol);
val(y,lca,sol);
fout<<sol<<'\n';
}
return 0;
}