#include <bits/stdc++.h>
#define dbg() cerr <<
#define name(x) (#x) << ": " << (x) << ' ' <<
using namespace std;
struct SegmTree {
int n;
vector<int> tree;
SegmTree(const vector<int> &v) : n(v.size()), tree(2 * n) {
for (int i = 0; i < n; ++i) {
tree[i + n] = v[i];
}
for (int i = n - 1; i >= 1; --i) {
tree[i] = max(tree[2 * i], tree[2 * i + 1]);
}
}
void Update(int pos, int val) {
for (tree[pos += n] = val; pos/= 2; ) {
tree[pos] = max(tree[2 * pos], tree[2 * pos + 1]);
}
}
int Query(int l, int r) {
int ans = 0; ++r;
for (l += n, r += n; l < r; l /= 2, r /= 2) {
if (l & 1) ans = max(ans, tree[l++]);
if (r & 1) ans = max(ans, tree[--r]);
}
return ans;
}
};
void Precalc(int node, vector<int> &par, vector<int> &depth, vector<int> &sz, vector<vector<int>> &adj) {
sz[node] = 1;
for (int &x : adj[node]) {
adj[x].erase(find(adj[x].begin(), adj[x].end(), node));
par[x] = node;
depth[x] = depth[node] + 1;
Precalc(x, par, depth, sz, adj);
sz[node] += sz[x];
if (sz[x] > sz[adj[node][0]]) {
swap(adj[node][0], x);
}
}
}
void DFS(int node, vector<int> &in, vector<int> &nxt, const vector<vector<int>> &adj) {
static int timer = 0;
in[node] = timer++;
for (auto &x : adj[node]) {
nxt[x] = x == adj[node][0] ? nxt[node] : x;
DFS(x, in, nxt, adj);
}
}
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];
}
vector<vector<int>> adj(n);
for (int i = 0; i < n - 1; ++i) {
int a, b; cin >> a >> b; --a, --b;
adj[a].emplace_back(b);
adj[b].emplace_back(a);
}
vector<int> par(n), depth(n), sz(n), in(n), nxt(n);
Precalc(0, par, depth, sz, adj);
DFS(0, in, nxt, adj);
vector<int> v(n);
for (int i = 0; i < n; ++i) {
v[in[i]] = val[i];
}
SegmTree st(v);
while (m--) {
int t, x, y; cin >> t >> x >> y;
if (t == 0) {
st.Update(in[x - 1], y);
} else {
--x, --y;
int ans = 0;
while (nxt[x] != nxt[y]) {
if (depth[nxt[x]] < depth[nxt[y]]) swap(x, y);
ans = max(ans, st.Query(in[nxt[x]], in[x]));
x = par[nxt[x]];
}
if (depth[x] < depth[y]) swap(x, y);
ans = max(ans, st.Query(in[y], in[x]));
cout << ans << '\n';
}
}
}