# include <algorithm>
# include <cstdio>
# include <vector>
using namespace std;
const char *FIN = "heavypath.in", *FOU = "heavypath.out";
const int MAX = 100005;
vector <int> G[MAX], L[MAX];
int N, M, v[MAX], lev[MAX], levL[MAX], T[MAX], big[MAX], path[MAX], lant[MAX], dp[MAX], ai[MAX << 2];
bool viz[MAX];
void dfs (int nod) {
int leaf = 1, most = -1;
viz[nod] = dp[nod] = 1;
for (vector <int> :: iterator it = G[nod].begin (); it != G[nod].end (); ++it) {
if (viz[*it] == 0) {
lev[*it] = lev[nod] + 1, dfs (*it), leaf = 0;
dp[nod] += dp[*it], most = (most == -1 || dp[most] < dp[*it]) ? *it : most;
}
}
if (leaf) {
big[lant[nod] = ++big[0]] = 1;
L[big[0]].push_back (nod);
return ;
}
++big[lant[nod] = lant[most]], L[lant[nod]].push_back (nod);
for (vector <int> :: iterator it = G[nod].begin (); it != G[nod].end (); ++it) {
if (*it != most && lev[nod] <= lev[*it]) {
T[lant[*it]] = nod, levL[lant[*it]] = lev[nod];
}
}
}
inline int add (int a, int b) {
return a + b;
}
void buildtree (int nod, int st, int dr, int i, int aux) {
if (st == dr) {
ai[add (nod, aux)] = v[L[i][st - 1]];
return ;
}
int mij = st + dr >> 1;
buildtree (nod << 1, st, mij, i, aux);
buildtree (nod << 1 | 1, mij + 1, dr, i, aux);
ai[add (nod, aux)] = max (ai[add (nod << 1, aux)], ai[add (nod << 1 | 1, aux)]);
}
void update (int nod, int st, int dr, int poz, int val, int aux) {
if (st == dr) {
ai[add (nod, aux)] = val;
return ;
}
int mij = st + dr >> 1;
if (poz <= mij)
update (nod << 1, st, mij, poz, val, aux);
else
update (nod << 1 | 1, mij + 1, dr, poz, val, aux);
ai[add (nod, aux)] = max (ai[add (nod << 1, aux)], ai[add (nod << 1 | 1, aux)]);
}
int query (int nod, int st, int dr, int s1, int s2, int aux) {
if (s1 <= st && dr <= s2) {
return ai[add (nod, aux)];
}
int mij = st + dr >> 1;
return max (s1 <= mij ? query (nod << 1, st, mij, s1, s2, aux) : 0, mij < s2 ? query ((nod << 1) + 1, mij + 1, dr, s1, s2, aux) : 0);
}
int main (void) {
freopen (FIN, "r", stdin);
freopen (FOU, "w", stdout);
scanf ("%d %d", &N, &M);
for (int i = 1; i <= N; ++i)
scanf ("%d", v + i);
for (int i = 1, x, y; i < N; ++i) {
scanf ("%d %d", &x, &y);
G[x].push_back (y);
G[y].push_back (x);
}
dfs (lev[1] = 1);
for (int i = 1; i <= big[0]; ++i) {
reverse (L[i].begin (), L[i].end ());
buildtree (1, 1, big[i], i, path[i] = (i != 1 ? path[i - 1] + (big[i - 1] << 2) : 0));
}
for (int i = 1, z, x, y; i <= M; ++i) {
scanf ("%d %d %d", &z, &x, &y);
if (z) {
for (int sol = 0; ; x = T[lant[x]]) {
if (lant[x] == lant[y]) {
if (lev[x] > lev[y]) swap (x, y);
printf ("%d\n", max (sol, query (1, 1, big[lant[x]], lev[x] - levL[lant[x]], lev[y] - levL[lant[y]], path[lant[x]])));
break;
}
if (levL[lant[x]] < levL[lant[y]]) swap (x, y);
sol = max (sol, query (1, 1, big[lant[x]], 1, lev[x] - levL[lant[x]], path[lant[x]]));
}
} else {
update (1, 1, big[lant[x]], lev[x] - levL[lant[x]], y, path[lant[x]]);
}
}
}