#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
#include <functional>
std::ifstream fin("heavypath.in");
std::ofstream fout("heavypath.out");
int gs, q;
std::vector<std::vector<int>> adj_list;
int node_val[200005];
int depth[200005];
int sub_sz[200005];
int up[18][200005];
int heavy_child[200005];
bool heavy_parent[200005];
int label[200005];
int label_r[200005];
int tin[200005];
int tout[200005];
int top_of_chain[200005];
int segtree[800005];
void segtree_build(int node, int l, int r) {
if (l==r) {
segtree[node] = node_val[label_r[l]];
return;
}
int m = (l+r)>>1;
segtree_build(node<<1,l,m);
segtree_build(node<<1|1,m+1,r);
segtree[node] = std::max(segtree[node<<1], segtree[node<<1|1]);
}
void segtree_update(int node, int l, int r, int pos, int val) {
if (l==r) {
segtree[node] = val;
return;
}
int m = (l+r)>>1;
if (pos<=m) {
segtree_update(node<<1,l,m,pos,val);
}
else {
segtree_update(node<<1|1,m+1,r,pos,val);
}
segtree[node] = std::max(segtree[node<<1],segtree[node<<1|1]);
}
int segtree_query(int node, int l, int r, int st, int fi) {
if (l>fi||r<st) {
return -0x3f3f3f3f;
}
if (st<=l&&r<=fi) {
return segtree[node];
}
int m = (l+r)>>1;
return std::max(segtree_query(node<<1,l,m,st,fi), segtree_query(node<<1|1,m+1,r,st,fi));
}
int get_kth_ancestor(int node, int k) {
while (k) {
int l = 31-__builtin_clz(k);
node = up[l][node];
k ^= (1<<l);
}
return node;
}
int get_lca(int a, int b) {
if (depth[a]>depth[b]) {
std::swap(a,b);
}
b = get_kth_ancestor(b, depth[b]-depth[a]);
for (int lvl = 17; a != b;) {
while (lvl-1>=0&&up[lvl][a]==up[lvl][b]) {
--lvl;
}
a = up[lvl][a];
b = up[lvl][b];
}
return a;
}
void hld_update(int k, int v) {
node_val[k] = v;
segtree_update(1,1,gs,label[k],v);
}
int hld_query_subtree(int k) {
return segtree_query(1,1,gs,tin[k],tout[k]);
}
int hld_query_path(int a, int b) {
int lca = get_lca(a,b);
int ret = -0x3f3f3f3f;
for (auto k : {a, b}) {
while (depth[k] >= depth[lca]) {
if (heavy_parent[k]) {
int r = label[k];
int l = ((depth[top_of_chain[k]] >= depth[lca]) ? label[top_of_chain[k]] : label[lca]);
ret = std::max(ret, segtree_query(1,1,gs,l,r));
k = up[0][top_of_chain[k]];
}
else {
ret = std::max(ret, node_val[k]);
k = up[0][k];
}
}
}
return ret;
}
void read_data() {
fin >> gs >> q;
for (int i = 1; i <= gs; i++) {
fin >> node_val[i];
}
adj_list.resize(gs+1);
for (int i = 0, a, b; i < gs-1; i++) {
fin >> a >> b;
adj_list[a].emplace_back(b);
adj_list[b].emplace_back(a);
}
}
void dfs1(int k, int p) {
depth[k] = depth[p] + 1;
sub_sz[k] = 1;
up[0][k] = p;
for (int j = 1; j < 18; j++) {
up[j][k] = up[j-1][up[j-1][k]];
}
for (const auto& i : adj_list[k]) {
if (i!=p) {
dfs1(i,k);
sub_sz[k] += sub_sz[i];
if (sub_sz[i] > sub_sz[heavy_child[k]]) {
heavy_child[k] = i;
}
}
}
if (heavy_child[k]) {
heavy_parent[heavy_child[k]] = 1;
}
}
void dfs2(int k, int p, int& timer) {
label[k] = tin[k] = tout[k] = ++timer;
label_r[label[k]] = k;
if (heavy_child[k]) {
top_of_chain[heavy_child[k]] = top_of_chain[k];
dfs2(heavy_child[k],k,timer);
}
for (const auto& i : adj_list[k]) {
if (i!=p&&i!=heavy_child[k]) {
top_of_chain[i] = i;
dfs2(i,k,timer);
}
}
tout[k] = timer;
}
void preprocess_tree() {
dfs1(1,0);
top_of_chain[1] = 1;
int timer = 0;
dfs2(1,0,timer);
segtree_build(1,1,gs);
}
void answer_queries() {
while (q--) {
int op;
fin >> op;
if (op==0) {
int k, v;
fin >> k >> v;
hld_update(k,v);
}
else {
int a, b;
fin >> a >> b;
fout << hld_query_path(a,b) << "\n";
}
}
}
int main() {
read_data();
preprocess_tree();
answer_queries();
}