#include <bits/stdc++.h>
using namespace std;
struct HeavyLight {
vector<vector<int>> G;
vector<int> jump, sub, depth, lin, parent;
HeavyLight(int n) : G(n), jump(n), sub(n),
depth(n), lin(n), parent(n) {}
void AddEdge(int a, int b) {
G[a].push_back(b);
G[b].push_back(a);
}
void Build() { dfs_sub(0, -1, 0); dfs_jump(0, 0); }
// Gets the position in the HL linearization
int GetPosition(int node) { return lin[node]; }
// Gets an array of ranges of form [li...ri)
// that correspond to the ranges you would need
// to query in the underlying structure
vector<pair<int, int>> GetPathRanges(int a, int b) {
vector<pair<int, int>> ret;
while (jump[a] != jump[b]) {
if (depth[jump[a]] < depth[jump[b]])
swap(a, b);
ret.emplace_back(lin[jump[a]], lin[a] + 1);
a = parent[jump[a]];
}
if (depth[a] < depth[b]) swap(a, b);
ret.emplace_back(lin[b], lin[a] + 1);
return ret;
}
int dfs_sub(int node, int par, int dep) {
sub[node] = 1; parent[node] = par; depth[node] = dep;
if (par != -1) {
G[node].erase(find(G[node].begin(), G[node].end(), par));
}
for (auto vec : G[node])
sub[node] += dfs_sub(vec, node, dep + 1);
return sub[node];
}
int timer = 0;
void dfs_jump(int node, int jmp) {
jump[node] = jmp; lin[node] = timer++;
if (G[node].empty()) return;
pair<int, int> best{-1, -1};
for (auto vec : G[node])
best = max(best, {sub[vec], vec});
dfs_jump(best.second, jmp);
for (auto vec : G[node]) if (vec != best.second)
dfs_jump(vec, vec);
}
};
class SegmTree {
vector<int> T;
int n;
public:
SegmTree(int n) : T(4 * n), 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 = 0;
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;
}
};
int main() {
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int n, m; fin >> n >> m;
SegmTree st(n);
HeavyLight hl(n);
vector<int> vals(n);
for (int i = 0; i < n; ++i) {
fin >> vals[i];
}
for (int i = 1; i < n; ++i) {
int a, b; fin >> a >> b;
hl.AddEdge(a - 1, b - 1);
}
hl.Build();
for (int i = 0; i < n; ++i)
st.Update(hl.GetPosition(i), vals[i]);
while (m--) {
int t, a, b;
fin >> t >> a >> b;
if (t == 0) {
st.Update(hl.GetPosition(a - 1), b);
} else {
int ans = 0;
for (auto p : hl.GetPathRanges(a - 1, b - 1)) {
assert(p.first < p.second);
ans = max(ans, st.Query(p.first, p.second));
}
fout << ans << '\n';
}
}
return 0;
}