#include <fstream>
#include <vector>
#include <algorithm>
std::ifstream fin("heavypath.in");
std::ofstream fout("heavypath.out");
const int MAX_N = 100000;
const int MAX_M = 100000;
int n, m;
int a[MAX_N];
std::vector<int> g[MAX_N];
int w[MAX_N], lvl[MAX_N], father[MAX_N];
int in[MAX_N], order[MAX_N];
int id[MAX_N], nxt[MAX_N];
struct query {
int t, x, y, ans;
} queries[MAX_M];
void read() {
fin >> n >> m;
for (int i = 0; i < n; i++) {
fin >> a[i];
}
for (int i = 1; i < n; i++) {
int u, v;
fin >> u >> v;
u--; v--;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 0; i < m; i++) {
fin >> queries[i].t >> queries[i].x >> queries[i].y;
queries[i].x--;
if (queries[i].t == 1) queries[i].y--;
}
}
void dfs_init(int node) {
w[node] = 1;
for (int & son : g[node]) {
g[son].erase(std::find(g[son].begin(), g[son].end(), node));
lvl[son] = lvl[node] + 1;
father[son] = node;
dfs_init(son);
w[node] += w[son];
if (w[son] > w[g[node][0]])
std::swap(son, g[node][0]);
}
}
int nr_lanturi = 1;
int cnt = 0;
void dfs_hld(int node) {
in[node] = cnt;
order[cnt++] = node;
for (int son : g[node]) {
id[son] = (son == g[node][0] ? id[node] : nr_lanturi++);
nxt[son] = (son == g[node][0] ? nxt[node] : son);
dfs_hld(son);
}
}
namespace AINT {
int aint[4 * MAX_N];
void build(int node, int l, int r) {
if (l == r)
return void(aint[node] = a[order[l]]);
int mid = (l + r) / 2;
build(node * 2 + 1, l, mid);
build(node * 2 + 2, mid + 1, r);
aint[node] = std::max(aint[node * 2 + 1], aint[node * 2 + 2]);
}
void update(int node, int l, int r, int pos) {
if (l == r)
return void(aint[node] = a[order[l]]);
int mid = (l + r) / 2;
if (pos <= mid)
update(node * 2 + 1, l, mid, pos);
else update(node * 2 + 2, mid + 1, r, pos);
aint[node] = std::max(aint[node * 2 + 1], aint[node * 2 + 2]);
}
int query(int node, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr)
return aint[node];
int mid = (l + r) / 2;
if (ql <= mid && mid < qr)
return std::max(query(node * 2 + 1, l, mid, ql, qr), query(node * 2 + 2, mid + 1, r, ql, qr));
if (ql <= mid)
return query(node * 2 + 1, l, mid, ql, qr);
return query(node * 2 + 2, mid + 1, r, ql, qr);
}
}
int query(int x, int y) {
int ans = 0;
while (id[x] != id[y]) {
if (lvl[nxt[x]] < lvl[nxt[y]]) std::swap(x, y);
ans = std::max(ans, AINT::query(0, 0, n - 1, in[nxt[x]], in[x]));
x = father[nxt[x]];
}
if (lvl[x] > lvl[y]) std::swap(x, y);
ans = std::max(ans, AINT::query(0, 0, n - 1, in[x], in[y]));
return ans;
}
void solve() {
dfs_init(0);
dfs_hld(0);
AINT::build(0, 0, n - 1);
for (auto & [t, x, y, ans]: queries) {
if (t == 0) {
a[x] = y;
AINT::update(0, 0, n - 1, in[x]);
} else {
ans = query(x, y);
}
}
}
void write() {
for (auto [t, x, y, ans] : queries) {
if (t == 1)
fout << ans << '\n';
}
}
int main() {
read();
solve();
write();
return 0;
}