#include <fstream>
#include <vector>
using namespace std;
const int N = 1e5 + 5;
int v[N], sz[N], h_chi[N], par[N], dep[N], idx[N], top[N], aint[4 * N], t, n;
vector<int> gr[N];
void dfs_init(int nod) {
sz[nod] = 1;
for (auto vec : gr[nod]) {
if (vec != par[nod]) {
par[vec] = nod;
dep[vec] = dep[nod] + 1;
dfs_init(vec);
sz[nod] += sz[vec];
if (sz[vec] > sz[h_chi[nod]]) {
h_chi[nod] = vec;
}
}
}
}
void dfs_hf(int nod) {
idx[nod] = ++t;
if (h_chi[nod] != 0) {
top[h_chi[nod]] = top[nod];
dfs_hf(h_chi[nod]);
}
for (auto vec : gr[nod]) {
if (vec != par[nod] && vec != h_chi[nod]) {
top[vec] = vec;
dfs_hf(vec);
}
}
}
void update(int p, int st, int dr, int poz, int val) {
if (st == dr) {
aint[p] = val;
return;
}
int m = (st + dr) / 2;
if (poz <= m) {
update(p * 2, st, m, poz, val);
} else {
update(p * 2 + 1, m + 1, dr, poz, val);
}
aint[p] = max(aint[p * 2], aint[p * 2 + 1]);
}
int query(int p, int st, int dr, int x, int y) {
if (st >= x && dr <= y) {
return aint[p];
}
int m = (st + dr) / 2, ret = 0;
if (x <= m) {
ret = query(p * 2, st, m, x, y);
}
if (y > m) {
ret = max(ret, query(p * 2 + 1, m + 1, dr, x, y));
}
return ret;
}
int query(int x, int y) {
if (top[x] == top[y]) {
if (dep[x] > dep[y]) {
swap(x, y);
}
return query(1, 1, n, idx[x], idx[y]);
}
if (dep[top[x]] > dep[top[y]]) {
swap(x, y);
}
return max(query(1, 1, n, idx[top[y]], idx[y]), query(x, par[top[y]]));
}
int main() {
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int q;
cin >> n >> q;
for (int i = 1; i <= n; ++i) {
cin >> v[i];
}
for (int i = 1; i <= n - 1; ++i) {
int x, y;
cin >> x >> y;
gr[x].push_back(y);
gr[y].push_back(x);
}
dfs_init(1);
top[1] = 1;
dfs_hf(1);
for (int i = 1; i <= n; ++i) {
update(1, 1, n, idx[i], v[i]);
}
while (q--) {
int op, x, y;
cin >> op >> x >> y;
if (op == 0) {
update(1, 1, n, idx[x], y);
} else {
cout << query(x, y) << "\n";
}
}
cin.close();
cout.close();
return 0;
}