#include <bits/stdc++.h>
using namespace std;
class HeavyLight {
struct Node {
int jump, subsize, depth, lin, parent;
vector<int> leg;
};
vector<Node> T;
bool processed;
public:
HeavyLight(int n) : T(n) {}
void AddEdge(int a, int b) {
T[a].leg.push_back(b);
T[b].leg.push_back(a);
}
void Preprocess() {
dfs_sub(0, -1);
dfs_jump(0, 0);
processed = true;
}
int GetLCA(int a, int b) {
assert(processed);
while (T[a].jump != T[b].jump) {
if (T[T[a].jump].depth > T[T[b].jump].depth)
a = T[T[a].jump].parent;
else
b = T[T[b].jump].parent;
}
return T[a].depth > T[b].depth ? b : a;
}
// Gets the position in the HL linearization
int GetPosition(int node) {
assert(processed);
return T[node].lin;
}
// 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) {
assert(processed);
vector<pair<int, int>> ret;
while (T[a].jump != T[b].jump) {
if (T[T[a].jump].depth < T[T[b].jump].depth)
swap(a, b);
ret.emplace_back(T[T[a].jump].lin, T[a].lin + 1);
a = T[T[a].parent].jump;
}
if (T[a].depth < T[b].depth) swap(a, b);
ret.emplace_back(T[b].lin, T[a].lin + 1);
return ret;
}
private:
int dfs_sub(int x, int par) {
auto &node = T[x];
node.subsize = 1;
node.parent = par;
if (par != -1) {
node.leg.erase(find(begin(node.leg), end(node.leg), par));
node.depth = 1 + T[par].depth;
}
for (auto vec : node.leg)
node.subsize += dfs_sub(vec, x);
return node.subsize;
}
int timer = 0;
void dfs_jump(int x, int jump) {
auto &node = T[x];
node.jump = jump;
node.lin = timer++;
iter_swap(begin(node.leg), max_element(begin(node.leg), end(node.leg),
[&](int a, int b) { return T[a].subsize < T[b].subsize; }));
for (auto vec : node.leg)
dfs_jump(vec, vec == node.leg.front() ? jump : vec);
}
};
class SegmTree {
vector<int> T;
int n;
public:
SegmTree(int n) : T(2 * 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() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int n, m; cin >> n >> m;
SegmTree st(n);
HeavyLight hl(n);
vector<int> vals(n);
for (int i = 0; i < n; ++i) {
cin >> vals[i];
}
for (int i = 1; i < n; ++i) {
int a, b; cin >> a >> b;
hl.AddEdge(a - 1, b - 1);
}
hl.Preprocess();
for (int i = 0; i < n; ++i)
st.Update(hl.GetPosition(i), vals[i]);
while (m--) {
int t, a, b;
cin >> 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))
ans = max(ans, st.Query(p.first, p.second));
cout << ans << '\n';
}
}
return 0;
}