#include <iostream>
#include <cstdio>
#include <vector>
#define NMAX 100005
using namespace std;
int N,M;
int valori[NMAX];
vector<int> arbore[NMAX];
vector<vector<int> > lant;
vector<vector<int> > intervale;
int viz[NMAX];
int greutati[NMAX];
int apartine[NMAX];
int poz_in_lant[NMAX];
int t_lant[NMAX];
int nivel[NMAX];
void citire()
{
scanf("%d%d",&N,&M);
for(int i=1; i<=N; i++)
scanf("%d",&valori[i]);
for(int i=1; i<=N-1; i++)
{
int x,y;
scanf("%d%d",&x,&y);
arbore[x].push_back(y);
arbore[y].push_back(x);
}
}
vector<int> aux;
void dfs(int nod,int t)
{
nivel[nod]=nivel[t]+1;
greutati[nod]=1;
int greutate_maxima_fii=-1;
int fiu_maxim=-1;
for(vector<int>::iterator ii=arbore[nod].begin(); ii!=arbore[nod].end(); ii++)
if(*ii != t)
{
dfs(*ii,nod);
greutati[nod]+=greutati[*ii];
if(greutate_maxima_fii < greutati[*ii])
{
greutate_maxima_fii = greutati[*ii];
fiu_maxim = *ii;
}
}
if(greutate_maxima_fii==-1) ///e frunza
{
aux.clear();
aux.push_back(nod);
lant.push_back(aux);
apartine[nod]=lant.size()-1;
t_lant[apartine[nod]]=t;
poz_in_lant[nod]=1;
}
else
{
apartine[nod]=apartine[fiu_maxim];
lant[apartine[nod]].push_back(nod);
t_lant[apartine[nod]]=t;
poz_in_lant[nod]=lant[apartine[nod]].size();
}
}
void update(vector<int> &interval,int val,int st,int dr,int nod_curent, int poz)
{
if(st==dr)
{
interval[nod_curent]=val;
return;
}
int mij = (st+dr)/2;
if(poz<=mij)
update(interval,val,st,mij,nod_curent*2,poz);
else
update(interval,val,mij+1,dr,nod_curent*2+1,poz);
interval[nod_curent] = max(interval[nod_curent*2],interval[nod_curent*2+1]);
}
void query(vector<int> &interval,int x,int y,int st,int dr, int nod_curent, int &maxim)
{
if(x<=st && dr<=y)
{
maxim = max(maxim,interval[nod_curent]);
return;
}
int mij = (st+dr)/2;
if(x <= mij)
query(interval,x,y,st,mij,nod_curent*2,maxim);
if(mij < y)
query(interval,x,y,mij+1,dr,nod_curent*2+1,maxim);
}
int rezolvaQ(int x,int y)
{
int n1,n2;
int maxim = 0;
n1 = nivel[t_lant[apartine[x]]];
n2 = nivel[t_lant[apartine[y]]];
while(apartine[x] != apartine[y])
{
int m = 0;
if(n1 > n2)
{
int p1 = poz_in_lant[x];
query(intervale[apartine[x]],p1,lant[apartine[x]].size(),1,lant[apartine[x]].size(),1,m);
x = t_lant[apartine[x]];
}
else
{
int p2 = poz_in_lant[y];
query(intervale[apartine[y]],p2,lant[apartine[y]].size(),1,lant[apartine[y]].size(),1,m);
y = t_lant[apartine[y]];
}
maxim = max(maxim,m);
n1 = nivel[t_lant[apartine[x]]];
n2 = nivel[t_lant[apartine[y]]];
}
int m = 0;
int p1 = poz_in_lant[x];
int p2 = poz_in_lant[y];
query(intervale[apartine[x]],min(p1,p2),max(p1,p2),1,lant[apartine[x]].size(),1,m);
maxim = max(maxim,m);
return maxim;
}
void genereaza()
{
for(int i=0; i<lant.size(); i++)
{
vector<int> aux;
int n = lant[i].size();
aux.resize(n*4+1,0);
intervale.push_back(aux);
for(int j=0; j<n; j++)
update(intervale[i],valori[lant[i][j]],1,n,1,j+1);
}
}
void rezolva()
{
for(int i=1; i<=M; i++)
{
int q,x,y;
scanf("%d%d%d",&q,&x,&y);
if(q == 0)
{
update(intervale[apartine[x]],y,1,lant[apartine[x]].size(),1,poz_in_lant[x]);
}
else
{
int a = rezolvaQ(x,y);
printf("%d\n",a);
}
}
}
void debug()
{
for(int i=0; i<lant.size(); i++)
{
for(int j=0; j<lant[i].size(); j++)
cout<<lant[i][j]<<" ";
cout<<"| "<<t_lant[i];
cout<<endl;
}
}
void debug2()
{
for(int i=0; i<intervale.size(); i++)
{
cout<<i+1<<": ";
for(int j=1; j<=7; j++)
cout<<intervale[i][j]<<" ";
cout<<endl;
}
}
int main()
{
freopen("heavypath.in","r",stdin);
freopen("heavypath.out","w",stdout);
citire();
dfs(1,0);
genereaza();
//debug();
rezolva();
return 0;
}