#include <bits/stdc++.h>
using namespace std;
const int NMAX = 1e5 + 5;
int dep[NMAX],pr[NMAX],sz[NMAX],pos[NMAX],c[NMAX],head[NMAX];
int aint[NMAX * 4];
int val[NMAX];
vector <int> e[NMAX];
int ind = 0,t = 0,n;
void dfs(int u, int p) {
dep[u] = 1 + dep[p];
pr[u] = p;
sz[u] = 1;
for (int v : e[u]) {
if (v != p) {
dfs(v, u);
sz[u] += sz[v];
}
}
}
void heavy_dfs(int u, int p, int idx) {
pos[u] = ++t;
c[u] = ind;
for (int v : e[u]) {
if (v != p) {
if (sz[v] > sz[u] / 2)
heavy_dfs(v, u, idx);
}
}
for (int v: e[u]) {
if (v != p) {
if (sz[v] <= sz[u] / 2) {
ind++;
head[ind] = v;
heavy_dfs(v, u, ind);
}
}
}
}
void update(int node, int tl, int tr, int pos, int val) {
if (tr < pos || tl > pos)
return;
if (tl == tr) {
aint[node] = val;
return;
}
int tm = (tl + tr) / 2;
update(node * 2, tl, tm, pos, val);
update(node * 2 + 1, tm + 1, tr, pos, val);
aint[node] = max(aint[node * 2], aint[node * 2 + 1]);
}
int query(int node, int tl, int tr, int a, int b) {
if (tr < a || tl > b)
return 0;
if (a <= tl && tr <= b)
return aint[node];
int tm = (tl + tr) / 2;
int v1 = query(node * 2, tl, tm, a, b);
int v2 = query(node * 2 + 1, tm + 1, tr, a, b);
return max(v1, v2);
}
int solve(int a, int b) {
int ans = 0;
while (c[a] != c[b]) {
if (dep[head[c[a]]] < dep[head[c[b]]])
swap(a, b);
ans = max(ans, query(1, 1, n, pos[head[c[a]]], pos[a]));
a = pr[head[c[a]]];
}
if (pos[a] > pos[b])
swap(a, b);
ans = max(ans, query(1, 1, n, pos[a], pos[b]));
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int q,u,v,x;
fin >> n >> q;
for (int i = 1;i <= n;i++)
fin >> val[i];
for (int i = 0;i < n - 1;i++) {
fin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, 0);
ind = 1;
head[1] = 1;
heavy_dfs(1, 0, 1);
for (int i = 1;i <= n;i++)
update(1, 1, n, pos[i], val[i]);
while (q--) {
fin >> x >> u >> v;
if (x == 0)
update(1, 1, n, pos[u], v);
else
fout << solve(u, v) << '\n';
}
return 0;
}