#include <bits/stdc++.h>
#define MAXN 100001
using namespace std;
vector <int> G[MAXN], P[MAXN], aint[MAXN];
int n, paths, weight[MAXN], path[MAXN], father[MAXN], depth[MAXN], pos[MAXN], dim[MAXN], value[MAXN];
int answer, position, val, l1, l2;
void build(int index, int node, int left, int right) {
if(left == right) {
aint[index][node] = value[P[index][left-1]];
return;
}
int middle = (left + right)/2;
build(index, node*2, left, middle);
build(index, node*2+1, middle+1, right);
aint[index][node] = max(aint[index][node*2], aint[index][node*2+1]);
}
void DFS(int node) {
bool leaf = 1;
int maxWeight = 0;
weight[node] = 1;
for(int son: G[node]) {
if(son != father[node]) {
leaf = 0;
depth[son] = depth[node] + 1;
father[son] = node;
DFS(son);
weight[node] += weight[son];
if(weight[maxWeight] < weight[son])
maxWeight = son;
}
}
if(leaf) {
paths++;
P[paths].push_back(node);
path[node] = paths;
dim[paths] = 1;
return;
}
P[path[maxWeight]].push_back(node);
path[node] = path[maxWeight];
dim[path[node]] ++;
}
void makePaths() {
for(int i=1; i<=paths; ++i) {
reverse(P[i].begin(), P[i].end());
for(int j=0; j<dim[i]; ++j)
pos[P[i][j]] = j+1;
aint[i].push_back(0);
for(int j=1; j<=4 * dim[i]; ++j)
aint[i].push_back(0);
build(i, 1, 1, dim[i]);
}
}
void update(int index, int node, int left, int right) {
if(left == right) {
aint[index][node] = val;
return;
}
int middle = (left + right)/2;
if(position <= middle) update(index, node*2, left, middle);
else update(index, node*2+1, middle+1, right);
aint[index][node] = max(aint[index][node*2], aint[index][node*2+1]);
}
void query(int index, int node, int left, int right) {
if(l1 <= left && right <= l2) {
answer = max(answer, aint[index][node]);
return;
}
int middle = (left + right)/2;
if(l1 <= middle) query(index, node*2, left, middle);
if(l2 > middle) query(index, node*2+1, middle+1, right);
}
int searchInTree(int node1, int node2) {
int dad1, dad2, x, y;
answer = 0;
x = node1;
y = node2;
dad1 = P[path[node1]][0];
dad2 = P[path[node2]][0];
while(path[x] != path[y]) {
if(depth[dad1] < depth[dad2])
swap(x, y), swap(dad1, dad2);
l1 = 1;
l2 = pos[x];
query(path[x], 1, 1, dim[path[x]]);
x = father[dad1];
dad1 = P[path[x]][0];
dad2 = P[path[y]][0];
}
l1 = min(pos[x], pos[y]);
l2 = max(pos[x], pos[y]);
query(path[x], 1, 1, dim[path[x]]);
return answer;
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int type, q, i, x, y;
scanf("%d%d", &n, &q);
for(i=1; i<=n; ++i)
scanf("%d", &value[i]);
for(i=1; i<n; ++i) {
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
depth[1] = 1;
DFS(1);
makePaths();
/*
for(i=1; i<=paths; ++i) {
printf("Pentru lantul %d: ", i);
for(int j = 0; j<dim[i]; ++j)
printf("%d ", P[i][j]);
printf("\n");
}*/
while(q--) {
scanf("%d%d%d", &type, &x, &y);
if(type == 0) {
position = pos[x];
val = y;
value[x] = y;
update(path[x], 1, 1, dim[path[x]]);
} else printf("%d\n", searchInTree(x, y));
}
return 0;
}