#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>
using namespace std;
struct SegmentTree {
SegmentTree(int size) : size(size), data(size * 2, 0) {}
void update(int pos, int value) {
for (data[pos += size] = value; pos; pos /= 2)
data[pos / 2] = max(data[pos], data[pos ^ 1]);
}
int query(int l, int r) {
int answer = 0;
for (l += size, r += size; l < r; l /= 2, r /= 2) {
if (l % 2)
answer = max(answer, data[l++]);
if (r % 2)
answer = max(answer, data[--r]);
}
return answer;
}
int size;
vector<int> data;
};
struct HLD {
HLD(int size)
: value(size), edges(size), time(size), start(size), link(size),
segment_tree(size) {}
int size() const { return edges.size(); }
void add_edge(int x, int y) {
edges[x].push_back(y);
edges[y].push_back(x);
}
void prepare() {
dfs_size(0);
dfs_time(0, 0, 0);
for (int i = 0; i < size(); ++i)
segment_tree.update(time[i], value[i]);
}
// returns subtree size
int dfs_size(int node, int parent = -1) {
auto p = find(edges[node].begin(), edges[node].end(), parent);
if (p != edges[node].end())
edges[node].erase(p);
int max_size = 0;
int total = 1;
for (auto it = edges[node].begin(); it != edges[node].end(); ++it) {
int sub = dfs_size(*it, node);
if (sub > max_size) {
iter_swap(it, edges[node].begin());
max_size = sub;
}
total += sub;
}
return total;
}
// returns next available slot
int dfs_time(int node, int pos, int chain_start) {
time[node] = pos;
start[node] = chain_start;
if (edges[node].empty())
return pos + 1;
link[edges[node][0]] = link[node];
int next = dfs_time(edges[node][0], pos + 1, chain_start);
for (auto it = edges[node].begin() + 1; it != edges[node].end(); ++it) {
link[*it] = node;
next = dfs_time(*it, next, next);
}
return next;
}
void update(int node, int value) { segment_tree.update(time[node], value); }
int query(int x, int y) {
int answer = 0;
while (start[x] != start[y]) {
if (start[x] < start[y])
swap(x, y);
answer = max(answer, segment_tree.query(start[x], time[x] + 1));
x = link[x];
}
if (time[x] > time[y])
swap(x, y);
answer = max(answer, segment_tree.query(time[x], time[y] + 1));
return answer;
}
vector<int> value;
vector<vector<int>> edges;
vector<int> time;
vector<int> start;
vector<int> link;
SegmentTree segment_tree;
};
int main() {
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
int N, M;
cin >> N >> M;
HLD graph(N);
for (int i = 0; i < N; ++i)
cin >> graph.value[i];
for (int i = 1; i < N; ++i) {
int x, y;
cin >> x >> y;
graph.add_edge(x - 1, y - 1);
}
graph.prepare();
for (int i = 0; i < M; ++i) {
int type, x, y;
cin >> type >> x >> y;
if (type == 0)
graph.update(x - 1, y);
else {
cout << graph.query(x - 1, y - 1) << "\n";
}
}
}