#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <fstream>
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN = 100005;
int N, M;
int vals[MAXN];
vector<int> adj[MAXN];
int parent[MAXN], depth[MAXN], sz[MAXN];
int heavy[MAXN], head[MAXN], pos[MAXN];
int arr[MAXN];
int tree[4 * MAXN];
int cur_pos;
void dfs_sz(int u, int p, int d) {
sz[u] = 1;
parent[u] = p;
depth[u] = d;
int max_sz = -1;
heavy[u] = -1;
for (int v : adj[u]) {
if (v != p) {
dfs_sz(v, u, d + 1);
sz[u] += sz[v];
if (sz[v] > max_sz) {
max_sz = sz[v];
heavy[u] = v;
}
}
}
}
void dfs_hld(int u, int h) {
head[u] = h;
pos[u] = ++cur_pos;
arr[cur_pos] = vals[u];
if (heavy[u] != -1) {
dfs_hld(heavy[u], h);
}
for (int v : adj[u]) {
if (v != parent[u] && v != heavy[u]) {
dfs_hld(v, v);
}
}
}
void build(int node, int start, int end) {
if (start == end) {
tree[node] = arr[start];
} else {
int mid = (start + end) / 2;
build(2 * node, start, mid);
build(2 * node + 1, mid + 1, end);
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
}
void update_tree(int node, int start, int end, int idx, int val) {
if (start == end) {
tree[node] = val;
} else {
int mid = (start + end) / 2;
if (start <= idx && idx <= mid) {
update_tree(2 * node, start, mid, idx, val);
} else {
update_tree(2 * node + 1, mid + 1, end, idx, val);
}
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
}
int query_tree(int node, int start, int end, int l, int r) {
if (r < start || end < l) {
return -1;
}
if (l <= start && end <= r) {
return tree[node];
}
int mid = (start + end) / 2;
return max(query_tree(2 * node, start, mid, l, r),
query_tree(2 * node + 1, mid + 1, end, l, r));
}
int query_path(int u, int v) {
int res = -1;
for (; head[u] != head[v]; u = parent[head[u]]) {
if (depth[head[u]] < depth[head[v]]) swap(u, v);
res = max(res, query_tree(1, 1, N, pos[head[u]], pos[u]));
}
if (depth[u] > depth[v]) swap(u, v);
res = max(res, query_tree(1, 1, N, pos[u], pos[v]));
return res;
}
int main() {
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
fin >> N >> M;
for (int i = 1; i <= N; ++i) {
fin >> vals[i];
}
for (int i = 0; i < N - 1; ++i) {
int u, v;
fin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
cur_pos = 0;
dfs_sz(1, 0, 0);
dfs_hld(1, 1);
build(1, 1, N);
for (int i = 0; i < M; ++i) {
int op, x, y;
fin >> op >> x >> y;
if (op == 0) {
update_tree(1, 1, N, pos[x], y);
vals[x] = y;
} else {
fout << query_path(x, y) << "\n";
}
}
fin.close();
return 0;
}