#include <fstream>
#include <vector>
#include <iostream>
class FenwickTree {
private:
int size;
std::vector <int> vec;
void ReplacePirv (int nod, int st, int dr, int pos, int val) {
if (st == dr) {
vec[nod] = val;
}
else {
int mij = (st + dr) / 2;
if (pos <= mij) {
ReplacePirv(2 * nod + 1, st, mij, pos, val);
}
else {
ReplacePirv(2 * nod + 2, mij + 1, dr, pos, val);
}
vec[nod] = std::max(vec[2 * nod + 1], vec[2 * nod + 2]);
}
}
int MaximumPriv (int nod, int st, int dr, int pos1, int pos2) {
if (st == pos1 && dr == pos2) {
return vec[nod];
}
else {
int mij = (st + dr) / 2;
int ans = -1;
if (pos1 <= mij) {
ans = MaximumPriv(2 * nod + 1, st, mij, pos1, std::min(pos2, mij));
}
if (mij + 1 <= pos2) {
ans = std::max(ans, MaximumPriv(2 * nod + 2, mij + 1, dr, std::max(pos1, mij + 1), pos2));
}
return ans;
}
}
public:
FenwickTree (int set_size) {
size = set_size;
vec.resize(4 * size + 60, 0);
}
void Replace (int pos, int val) {
ReplacePirv(0, 0, size - 1, pos, val);
}
int Maximum (int pos1, int pos2) {
return MaximumPriv(0, 0, size - 1, pos1, pos2);
}
};
class FormTree {
public:
struct MiniNode {
std::vector <int> chd;
};
private:
int size;
std::vector <MiniNode> vec;
public:
FormTree (int set_size) {
size = set_size;
vec.resize(size);
}
void AddEdge (int node1, int node2) {
vec[node1].chd.push_back(node2);
vec[node2].chd.push_back(node1);
}
int GetSize () const {
return size;
}
const std::vector <MiniNode> &GetGraph () const {
return vec;
}
};
class SolidTree {
public:
struct Node {
std::vector <int> par;
std::vector <int> chd;
int sub_size = 0;
int depth = 0;
};
private:
int size;
std::vector <Node> vec;
void InitDFS (int node, int par) {
if (par == -1) {
vec[node].depth = 0;
}
else {
vec[node].depth = vec[par].depth + 1;
vec[node].par.push_back(par);
while (vec[vec[node].par.back()].par.size() >= vec[node].par.size()) {
vec[node].par.push_back(vec[vec[node].par.back()].par[vec[node].par.size() - 1]);
}
}
vec[node].sub_size = 1;
for (int i = 0; i < vec[node].chd.size(); i++) {
if (vec[node].chd[i] == par) {
std::swap(vec[node].chd[i], vec[node].chd.back());
vec[node].chd.pop_back();
i--;
continue;
}
InitDFS(vec[node].chd[i], node);
vec[node].sub_size += vec[vec[node].chd[i]].sub_size;
}
}
public:
SolidTree (const FormTree &solidify) {
size = solidify.GetSize();
const std::vector <FormTree::MiniNode> &temp_vec = solidify.GetGraph();
vec.resize(size);
for (int i = 0; i < size; i++) {
vec[i].chd = temp_vec[i].chd;
}
InitDFS(0, -1);
}
Node GetNode (int node) {
return vec[node];
}
int GetPar (int node, int target) {
if (vec[node].depth > target) {
int log_size = 31 - __builtin_clz(vec[node].depth - target);
for (int bit = log_size; bit >= 0; bit--) {
if (vec[node].depth - target >= 1 << bit) {
node = vec[node].par[bit];
}
}
}
return node;
}
int GetLCA (int node1, int node2) {
if (vec[node1].depth < vec[node2].depth) {
std::swap(node1, node2);
}
node1 = GetPar(node1, vec[node2].depth);
if (node1 == node2) {
return node1;
}
int log_size = 31 - __builtin_clz(vec[node1].depth);
for (int bit = log_size; bit >= 0; bit--) {
if (1 << bit < vec[node1].depth && vec[node1].par[bit] != vec[node2].par[bit]) {
node1 = vec[node1].par[bit];
node2 = vec[node2].par[bit];
}
}
return vec[node1].par[0];
}
};
class HeavyPath {
private:
int size;
FenwickTree aint;
SolidTree tree;
std::vector <int> vals;
int aint_cnt = 0;
std::vector <int> aint_pos;
std::vector <int> chain_top;
void ChainDFS (int node, int top) {
chain_top[node] = top;
SolidTree::Node myNode = tree.GetNode(node);
int max_chd = -1;
int max_size = -1;
int now_size;
for (int chd : myNode.chd) {
now_size = tree.GetNode(chd).sub_size;
if (now_size > max_size) {
max_chd = chd;
max_size = now_size;
}
}
aint_pos[node] = aint_cnt++;
aint.Replace(aint_pos[node], vals[node]);
if (max_chd != -1) {
ChainDFS(max_chd, top);
for (int chd : myNode.chd) {
if (max_chd == chd) {
continue;
}
ChainDFS(chd, chd);
}
}
}
int MaxClimb (int node, int min_depth) {
if (tree.GetNode(node).depth < min_depth) {
return -1;
}
int top = chain_top[node];
if (tree.GetNode(top).depth <= min_depth) {
top = tree.GetPar(node, min_depth);
return aint.Maximum(aint_pos[top], aint_pos[node]);
}
else {
int par_top = tree.GetNode(top).par[0];
return std::max(aint.Maximum(aint_pos[top], aint_pos[node]),
MaxClimb(par_top, min_depth));
}
}
public:
HeavyPath (const FormTree &tree_state, std::vector <int> &&get_vals) :
aint(tree_state.GetSize()), tree(tree_state) {
size = tree_state.GetSize();
vals = get_vals;
aint_pos.resize(size, 0);
chain_top.resize(size, 0);
ChainDFS(0, 0);
}
void Update (int node, int val) {
aint.Replace(aint_pos[node], val);
}
int Maximum (int node1, int node2) {
int lca = tree.GetLCA(node1, node2);
int lca_depth = tree.GetNode(lca).depth;
return std::max(MaxClimb(node1, lca_depth), MaxClimb(node2, lca_depth + 1));
}
};
int main () {
std::ifstream fin("heavypath.in");
std::ofstream fout("heavypath.out");
int n, m;
int i;
int val1, val2;
int task;
fin >> n >> m;
FormTree temp_tree(n);
std::vector <int> vals(n);
for (i = 0; i < n; i++) {
fin >> vals[i];
}
for (i = 0; i < n - 1; i++) {
fin >> val1 >> val2;
temp_tree.AddEdge(--val1, --val2);
}
HeavyPath solve(temp_tree, std::move(vals));
for (i = 0; i < m; i++) {
fin >> task >> val1 >> val2;
if (task == 0) {
solve.Update(--val1, val2);
}
else {
fout << solve.Maximum(--val1, --val2) << '\n';
}
}
return 0;
}