#include <bits/stdc++.h>
using namespace std;
const int MAX_V = 100005;
int n, m;
int nodes[MAX_V];
int siz[MAX_V];
int parrent[MAX_V];
int head[MAX_V];
int level[MAX_V];
int index[MAX_V];
int tree[MAX_V * 4];
vector < int > G[MAX_V];
vector < int > dfsOrder;
int querySegTree(int node, int lo, int ri, int st, int en) {
if (lo > ri) {
return INT_MIN;
}
if (st <= lo && ri <= en) {
return tree[node];
}
int mid = (lo + ri) / 2;
if (st > mid) {
return querySegTree(2 * node + 1, mid + 1, ri, st, en);
} else if (en <= mid) {
return querySegTree(2 * node, lo, mid, st, en);
} else {
return max(querySegTree(2 * node + 1, mid + 1, ri, st, en), querySegTree(2 * node, lo, mid, st, en));
}
}
void updateSegTree(int node, int lo, int ri, int pos, int value) {
if (lo > ri) {
return;
}
if (lo == ri) {
tree[node] = value;
return;
}
int mid = (lo + ri) / 2;
if (pos <= mid) {
updateSegTree(2 * node, lo, mid, pos, value);
} else {
updateSegTree(2 * node + 1, mid + 1, ri, pos, value);
}
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
void dfs(int u, int dad) {
siz[u] = 1;
parrent[u] = dad;
level[u] = level[dad] + 1;
for (int v : G[u]) {
if (v != dad) {
dfs(v, u);
siz[u] += siz[v];
}
}
}
void heavyDfs(int u) {
index[u] = int(dfsOrder.size()) + 1;
dfsOrder.push_back(u);
if (int(G[u].size()) == 0) {
return;
}
int heavySon = G[u][0];
if (int(G[u].size()) == 1 && int(G[u][0]) == parrent[u]) {
return;
} else {
if (int(G[u].size()) >= 2 && G[u][0] == parrent[u]) {
heavySon = G[u][1];
}
}
for (int v : G[u]) {
if (siz[heavySon] < siz[v] && v != heavySon && v != parrent[u]) {
heavySon = v;
}
}
head[heavySon] = head[u];
heavyDfs(heavySon);
for (int v : G[u]) {
if (v != heavySon && v != parrent[u]) {
heavyDfs(v);
}
}
}
void pp(int& u, int &v) {
if (index[u] > index[v]) {
swap(u, v);
}
return;
}
void update(int node, int val) {
updateSegTree(1, 1, n, index[node], val);
return;
}
int query(int u, int v) {
if (head[u] == head[v]) {
pp(u, v);
return querySegTree(1, 1, n, index[u], index[v]);
}
int ans = 0;
if (level[parrent[head[u]]] > level[parrent[head[v]]]) {
ans = querySegTree(1, 1, n, min(index[u], index[head[u]]), max(index[u], index[head[u]]));
u = parrent[head[u]];
} else {
ans = querySegTree(1, 1, n, min(index[v], index[head[v]]), max(index[v], index[head[v]]));
v = parrent[head[v]];
}
return max(ans, query(u, v));
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> nodes[i];
}
for (int i = 2; i <= n; ++i) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
for (int i = 1; i <= n; ++i) {
head[i] = i;
}
heavyDfs(1);
for (int i = 1; i <= n; ++i) {
update(i, nodes[i]);
}
while (m --) {
int t, u, v;
cin >> t >> u >> v;
if (t == 0) {
update(u, v);
} else if (t == 1) {
cout << query(u, v) << "\n";
}
}
return 0;
}