#include <bits/stdc++.h>
#define MAXN 100005
int N, Q;
int V[MAXN];
std::ifstream input ("heavypath.in");
std::ofstream output("heavypath.out");
#define LEFT 2*index
#define RIGHT 2*index+1
#define MIDDLE (left+right)/2
class HPD {
public:
HPD(const std::vector <std::vector <int>> &graph, int V[]) : graph(graph) {
this->V.resize(graph.size(), 0);
tree.resize(graph.size());
chain.resize(graph.size());
for (int i=1; i<graph.size(); ++i) this->V[i] = V[i];
order.resize(graph.size(), 0);
where.resize(graph.size(), 0);
parent.resize(graph.size(), 0);
rang.resize(graph.size(), 0);
level.resize(graph.size(), 0);
NChains = 0;
DFS();
buildTrees();
}
void update(int X, int Y) {
V[X] = Y;
update(where[X], order[X], 0, chain[where[X]].size()-1);
}
int query(int X, int Y) {
int ans = INT_MIN;
int A, B;
while (where[X] != where[Y]) {
if (level[chain[where[X]][0]] < level[chain[where[Y]][0]])
std::swap (X, Y);
A = 0, B = order[X];
ans = std::max(ans, query(where[X], A, B, 0, chain[where[X]].size()-1));
X = parent[chain[where[X]][0]];
} return std::max(ans, query(where[X], std::min(order[X], order[Y]), std::max(order[X], order[Y]), 0, chain[where[X]].size()-1));
}
private:
int NChains;
std::vector <int> V, order, where, parent, rang, level;
std::vector <std::vector <int>> tree, chain;
std::vector <std::vector <int>> graph;
void DFS(int vertex = 1, int height = 1) {
level[vertex] = height;
bool bLeaf = true;
int heavy = 0;
rang[vertex] = 1;
for (auto adj:graph[vertex])
if (!level[adj]) {
DFS(adj, height+1);
parent[adj] = vertex;
bLeaf = false;
if (rang[adj] > rang[heavy]) heavy = adj;
rang[vertex] += rang[adj];
}
if (bLeaf) where[vertex] = ++NChains;
else where[vertex] = where[heavy];
chain[where[vertex]].push_back(vertex);
}
void init(int treeidx, int left, int right, int index = 1) {
if (left == right) {
tree[treeidx][index] = V[chain[treeidx][left]];
return;
}
init (treeidx, left, MIDDLE, LEFT);
init (treeidx, MIDDLE+1, right, RIGHT);
tree[treeidx][index] = std::max(tree[treeidx][LEFT], tree[treeidx][RIGHT]);
}
void buildTrees() {
for (int i=1, j; i<=NChains; ++i) {
std::reverse(chain[i].begin(), chain[i].end());
for (j=0; j<chain[i].size(); ++j)
order[chain[i][j]] = j;
tree[i].resize(4*chain[i].size() + 5);
init(i, 0, chain[i].size()-1);
}
}
void update(int treeidx, int pos, int left, int right, int index = 1) {
if (left == right) {
tree[treeidx][index] = V[chain[treeidx][left]];
return;
}
if (pos <= MIDDLE) update(treeidx, pos, left, MIDDLE, LEFT);
else update(treeidx, pos, MIDDLE+1, right, RIGHT);
tree[treeidx][index] = std::max(tree[treeidx][LEFT], tree[treeidx][RIGHT]);
}
int query(int treeidx, int A, int B, int left, int right, int index = 1) {
if (A <= left && right <= B)
return tree[treeidx][index];
int max = INT_MIN;
if (A <= MIDDLE) max = query(treeidx, A, B, left, MIDDLE, LEFT);
if (MIDDLE < B) max = std::max(max, query(treeidx, A, B, MIDDLE+1, right, RIGHT));
return max;
}
};
int main()
{
input >> N >> Q;
for (int i=1; i<=N; ++i)
input >> V[i];
std::vector <std::vector <int>> graph;
graph.resize(N+1);
for (int i=1, X, Y; i<N; ++i)
input >> X >> Y, graph[X].push_back(Y), graph[Y].push_back(X);
auto hpd = HPD(graph, V);
for (int i=1, type, X, Y; i<=Q; ++i) {
input >> type >> X >> Y;
if (type) output << hpd.query(X, Y) << '\n';
else hpd.update(X, Y);
}
return 0;
}