#include <cstdio>
#include <algorithm>
#include <vector>
#include <fstream>
using namespace std;
#define MAXN 100010
int n, m, lanturi;
int a[MAXN], niv[MAXN], g[MAXN], nl[MAXN], aint[4 * MAXN];
bool v[MAXN];
int lTata[MAXN], lNiv[MAXN], d[MAXN], pozl[MAXN];
vector<int> G[MAXN], l[MAXN];
ifstream fin ("heavypath.in");
void read_graph() {
int i, x, y;
fin >> n >> m;
for (i = 1; i <= n; i++)
fin >> a[i];
for (i = 1; i < n; i++) {
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
}
void df(int nod) {
int hN = -1;
bool frunza = true;
vector<int>::iterator it;
v[nod] = true; g[nod] = 1;
for (it = G[nod].begin(); it != G[nod].end(); it++) {
if (not v[*it]) {
frunza = false;
niv[*it] = niv[nod] + 1;
df(*it);
g[nod] += g[*it];
if(hN == -1)
hN = *it;
else
if(g[hN] < g[*it])
hN = *it;
}
}
if (frunza) {
nl[nod] = ++lanturi;
d[lanturi] = 1;
l[lanturi].push_back(nod);
return;
}
nl[nod] = nl[hN];
d[nl[nod]]++;
l[nl[nod]].push_back(nod);
for (it = G[nod].begin(); it != G[nod].end(); it++) {
if (*it != hN /*and v[*it] /*niv[*it] >= niv[nod]*/) {
lTata[nl[*it]] = nod;
lNiv[nl[*it]] = niv[nod];
}
}
}
void build(int nod, int s, int d, int decalaj, int lant) {
int m;
if (s < d) {
m = (s + d) / 2;
build(nod * 2, s, m, decalaj, lant);
build(nod * 2 + 1, m + 1, d, decalaj, lant);
aint[nod + decalaj] = max(aint[nod * 2 + decalaj], aint[nod * 2 + 1 + decalaj]);
}
else
aint[nod + decalaj] = a[l[lant][s - 1]];
}
void make_paths() {
int i;
niv[1] = 1;
df(1);
for(i = 1; i <= lanturi; i++) {
reverse(l[i].begin(), l[i].end());
if (i > 1)
pozl[i] = pozl[i - 1] + d[i - 1] * 4;
build(1, 1, d[i], pozl[i], i);
}
}
void update(int nod, int left, int right, int poz, int val, int decalaj) {
if(left == right) {
aint[nod + decalaj] = val;
return;
}
int med = (left + right) / 2;
if(poz <= med)
update(nod * 2, left, med, poz, val, decalaj);
else
update(nod * 2 + 1, med + 1, right, poz, val, decalaj);
aint[nod + decalaj] = max(aint[nod * 2 + decalaj], aint[nod * 2 + 1 + decalaj]);
}
int query(int nod, int left, int right, int qleft, int qright, int decalaj) {
if(qleft <= left && right <= qright)
return aint[nod + decalaj];
int med = (left + right) / 2, rez = 0;
if(qleft <= med)
rez = max(rez, query(nod * 2, left, med, qleft, qright, decalaj));
if(med < qright)
rez = max(rez, query(nod * 2 + 1, med + 1, right, qleft, qright, decalaj));
return rez;
}
void solve() {
int t, x, y, sol = 0;
for (int i = 1; i <= m; ++i) {
fin >> t >> x >> y;
if (t == 0)
update(1, 1, d[nl[x]], niv[x] - lNiv[nl[x]], y, pozl[nl[x]]);
else {
sol = 0;
while (1) {
if (nl[x] == nl[y]) {
if (niv[x] > niv[y])
swap(x, y);
sol = max(sol, query(1, 1, d[nl[x]], niv[x] - lNiv[nl[x]], niv[y] - lNiv[nl[x]], pozl[nl[x]]));
break;
}
if (lNiv[nl[x]] < lNiv[nl[y]])
swap(x, y);
sol = max(sol, query(1, 1, d[nl[x]], 1, niv[x] - lNiv[nl[x]], pozl[nl[x]]));
x = lTata[nl[x]];
}
printf("%d\n", sol);
}
}
}
int main() {
freopen("heavypath.out", "w", stdout);
read_graph();
make_paths();
solve();
return 0;
}