#include <bits/stdc++.h>
using namespace std;
struct HeavyLight {
vector<int> jump, sub, depth, lin, parent;
vector<vector<int>> G;
bool processed = false;
HeavyLight(int n) :
jump(n), sub(n), depth(n), lin(n),
parent(n), G(n) {}
void AddEdge(int a, int b) {
G[a].push_back(b);
G[b].push_back(a);
}
void Preprocess() {
dfs_sub(0, -1);
dfs_jump(0, 0);
processed = true;
}
// Gets the position in the HL linearization
int GetPosition(int node) {
assert(processed);
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) {
assert(processed);
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 GetLCA(int a, int b) {
while (jump[a] != jump[b]) {
if (depth[jump[a]] < depth[jump[b]])
swap(a, b);
a = parent[jump[a]];
}
return depth[a] < depth[b] ? a : b;
}
int dfs_sub(int node, int par) {
sub[node] = 1; parent[node] = par;
if (par != -1) {
G[node].erase(find(G[node].begin(), G[node].end(), par));
depth[node] = 1 + depth[par];
}
for (auto vec : G[node])
sub[node] += dfs_sub(vec, node);
return sub[node];
}
int timer = 0;
void dfs_jump(int node, int j) {
jump[node] = j; lin[node] = timer++;
iter_swap(G[node].begin(), max_element(G[node].begin(), G[node].end(),
[&](int a, int b) { return sub[a] < sub[b]; }));
for (auto vec : G[node])
dfs_jump(vec, vec == G[node].front() ? j : vec);
}
};
map<int, int> CompressTree(HeavyLight& hl, vector<int> v) {
auto cmp = [&](int a, int b) {
return hl.lin[a] < hl.lin[b];
};
sort(v.begin(), v.end(), cmp);
for (int i = (int)v.size() - 1; i > 0; --i)
v.push_back(hl.GetLCA(v[i - 1], v[i]));
sort(v.begin(), v.end(), cmp);
v.erase(unique(v.begin(), v.end()), v.end());
map<int, int> ret;
for (int i = 0; i < (int)v.size(); ++i)
ret[v[i]] = (i == 0 ? -1 : hl.GetLCA(v[i - 1], v[i]));
return ret;
}
int main() {
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int n, m; cin >> n >> m;
vector<int> val(n);
for (int i = 0; i < n; ++i) {
cin >> val[i];
}
HeavyLight hl(n);
for (int i = 1; i < n; ++i) {
int a, b; cin >> a >> b;
hl.AddEdge(a - 1, b - 1);
}
hl.Preprocess();
cerr << "DONS" << endl;
const int kMagic = 512;
vector<int> aug(n);
for (int i = 0; i < m; i += kMagic) {
vector<tuple<int, int, int>> qs;
vector<int> sub;
for (int j = i; j < m && j < i + kMagic; ++j) {
int t, a, b; cin >> t >> a >> b;
sub.push_back(--a); if (t == 1) sub.push_back(--b);
qs.emplace_back(t, a, b);
}
sort(sub.begin(), sub.end());
sub.erase(unique(sub.begin(), sub.end()), sub.end());
auto T = CompressTree(hl, sub);
for (auto& p : T) {
int node = p.first, anc = p.second;
aug[node] = 0;
for (node = hl.parent[node]; node != anc; node = hl.parent[node])
aug[node] = max(aug[node], val[node]);
}
for (auto q : qs) {
int t, a, b; tie(t, a, b) = q;
if (t == 0) val[a] = b;
else {
int res = 0;
while (a != b) {
if (hl.depth[a] < hl.depth[b]) swap(a, b);
res = max(res, val[a]);
res = max(res, aug[a]);
a = T[a];
}
cout << max(res, val[a]) << '\n';
}
}
}
return 0;
}