// #include <debug.hpp>
#include <bits/stdc++.h>
using namespace std;
struct SegTree {
vector<int> T; int n;
SegTree(int n) : T(2 * n, (int)-2e9), n(n) {}
void Update(int pos, int val) {
for (T[pos += n] = val; pos > 1; pos /= 2)
T[pos / 2] = max(T[pos], T[pos ^ 1]);
}
int Query(int b, int e) {
int res = -2e9;
for (b += n, e += n; b < e; b /= 2, e /= 2) {
if (b % 2) res = max(res, T[b++]);
if (e % 2) res = max(res, T[--e]);
}
return res;
}
};
struct HeavyLight {
int n, timer;
vector<int> jump, sub, depth, enter, parent;
HeavyLight(auto& graph, int root = 0) :
n(graph.size()), jump(n), sub(n),
depth(n), enter(n), parent(n) {
for (auto phase : {0, 1})
timer = 0, dfs(graph, root, -1, 0, -1);
}
// Returns the position in the HL linearization
int Get(int node) { return enter[node]; }
// Runs a callback for all ranges [l, r] in the path
// a -> b. Some ranges might have l > r; if combining
// function is commutative just swap them.
template<typename Callback>
void QueryPath(int a, int b, Callback&& cb) {
if (jump[a] == jump[b]) {
cb(enter[a], enter[b]); // (*)
} else if (depth[jump[a]] > depth[jump[b]]) {
cb(enter[a], enter[jump[a]]);
QueryPath(parent[jump[a]], b, cb);
} else {
QueryPath(a, parent[jump[b]], cb);
cb(enter[jump[b]], enter[b]);
}
}
// Returns a range [l, r] corresponding to nodes in the
// subtree.
pair<int, int> QuerySubtree(int node) {
return {enter[node], enter[node] + sub[node] - 1};
}
int dfs(auto& graph, int node, int par, int dep, int jmp) {
if (jmp == -1) jmp = node;
parent[node] = par; depth[node] = dep; jump[node] = jmp;
enter[node] = timer++;
int heavy = 0, ret = 1;
for (auto& vec : graph[node]) {
if (vec == par) continue;
int now = dfs(graph, vec, node, dep + 1, jmp);
if (heavy < now) heavy = now, swap(vec, graph[node][0]);
ret += now; jmp = -1;
}
return sub[node] = ret;
}
};
int main() {
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int n, q; cin >> n >> q;
vector<int> v(n);
for (int i = 0; i < n; ++i)
cin >> v[i];
vector<vector<int>> graph(n);
for (int i = 1; i < n; ++i) {
int a, b; cin >> a >> b;
graph[a - 1].push_back(b - 1);
graph[b - 1].push_back(a - 1);
}
HeavyLight H(graph);
// debug(H.depth);
// debug(H.enter);
// vector<int> order(n);
// for (int i = 0; i < n; ++i)
// order[H.Get(i)] = i;
// debug(order);
SegTree st(n);
for (int i = 0; i < n; ++i)
st.Update(H.Get(i), v[i]);
vector<pair<int, int>> ranges;
for (int i = 0; i < q; ++i) {
int t, a, b; cin >> t >> a >> b;
if (t == 0) st.Update(H.Get(a - 1), b);
else {
int ans = -2e9;
H.QueryPath(a - 1, b - 1, [&](int l, int r) {
if (l > r) swap(l, r);
ans = max(ans, st.Query(l, r + 1));
});
cout << ans << '\n';
}
}
return 0;
}