#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> g[100005];
vector<int> pathuri[100005];
int carepath[100005];
int pozpath[100005];
int level[100005];
int tata[100005];
int dim[100005];
int parentul[100005];
int offset[100005];
int nr;
void dfs(int nod, int parent, int lvl)
{
level[nod]=lvl;
tata[nod]=parent;
dim[nod]=1;
int maxx=0,ii;
for(int i=0; i<g[nod].size(); i++)
if(level[g[nod][i]]==0){
dfs(g[nod][i], nod, lvl+1);
dim[nod]+=dim[g[nod][i]];
if(maxx<dim[g[nod][i]]){
maxx=dim[g[nod][i]];
ii=g[nod][i];
}
}
if(maxx==0){
pathuri[++nr].push_back(nod);
carepath[nod]=nr;
parentul[nr]=tata[nod];
}
else{
pathuri[carepath[ii]].push_back(nod);
carepath[nod]=carepath[ii];
parentul[carepath[ii]]=tata[nod];
}
}
struct Interval
{
int maxx;
};
int v[100005];
Interval arbint[400005];
int n;
Interval create(int value)
{
return Interval{
value,
};
}
Interval join(const Interval &left, const Interval &right)
{
return Interval{
max(left.maxx, right.maxx),
};
}
void update(int nod, int st, int dr, int index, int value, int add)
{
if(st==dr)
arbint[add+nod]=create(value);
else{
int mij=(st+dr)/2;
if(index<=mij)
update(2*nod, st, mij, index, value, add);
else
update(2*nod+1, mij+1, dr, index, value, add);
arbint[add+nod]=join(arbint[add+2*nod], arbint[add+2*nod+1]);
}
}
Interval query(int nod, int st, int dr, int left, int right, int add)
{
if(st==left && dr==right)
return arbint[add+nod];
else{
int mij=(st+dr)/2;
if(right<=mij)
return query(2*nod, st, mij, left, right, add);
else{
if(mij<left)
return query(2*nod+1, mij+1, dr, left, right, add);
else
return join(query(2*nod, st, mij, left, mij, add), query(2*nod+1, mij+1, dr, mij+1, right, add));
}
}
}
int main()
{ freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int n,m,i,x,y,j,tip,ans;
scanf("%d%d", &n, &m);
for(i=1; i<=n; i++)
scanf("%d", &v[i]);
for(i=1; i<n; i++){
scanf("%d%d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1, 0, 1);
for(i=1; i<=nr; i++){
offset[i]=offset[i-1]+4*pathuri[i-1].size();
for(j=0; j<pathuri[i].size()/2; j++){
swap(pathuri[i][j], pathuri[i][pathuri[i].size()-1-j]);
pozpath[pathuri[i][j]]=j;
pozpath[pathuri[i][pathuri[i].size()-1-j]]=pathuri[i].size()-1-j;
}
pozpath[pathuri[i][j]]=j;
}
for(i=1; i<=n; i++)
update(1, 0, pathuri[carepath[i]].size()-1, pozpath[i], v[i], offset[carepath[i]]);
for(i=1; i<=m; i++){
scanf("%d%d%d", &tip, &x, &y);
if(tip==0)
update(1, 0, pathuri[carepath[x]].size()-1, pozpath[x], y, offset[carepath[x]]);
else{
ans=0;
while(1){
if(carepath[x]==carepath[y]){
int a=min(pozpath[x], pozpath[y]);
int b=max(pozpath[x], pozpath[y]);
ans=max(ans, query(1, 0, pathuri[carepath[x]].size()-1, a, b, offset[carepath[x]]).maxx);
break;
}
else{
if(level[parentul[carepath[x]]]>level[parentul[carepath[y]]]){
int a=pozpath[x];
ans=max(ans, query(1, 0, pathuri[carepath[x]].size()-1, 0, a, offset[carepath[x]]).maxx);
x=parentul[carepath[x]];
}
else{
int a=pozpath[y];
ans=max(ans, query(1, 0, pathuri[carepath[y]].size()-1, 0, a, offset[carepath[y]]).maxx);
y=parentul[carepath[y]];
}
}
}
printf("%d\n", ans);
}
}
return 0;
}