#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define MAXN 100003
int n, nLevel;
int nodeValues[MAXN], used[MAXN], weight[MAXN], level[MAXN];
int pathF[MAXN], pathLevel[MAXN], pathPos[MAXN], pathDim[MAXN], l[MAXN];
vector<int> arcs[MAXN], path[MAXN];
int aint[4*MAXN];
void dfs(int current_node) {
used[current_node] = true;
weight[current_node] = 1;
bool is_leaf = true;
int next_node, hn = -1;
for(int i=0; i<arcs[current_node].size(); ++i)
if(! used[arcs[current_node][i]]) {
is_leaf = false;
next_node = arcs[current_node][i];
level[next_node] = level[current_node] + 1;
dfs(next_node);
weight[current_node] += weight[next_node];
if (hn == -1 || weight[hn] < weight[next_node])
hn = next_node;
}
if (is_leaf) {
++nLevel;
l[current_node] = nLevel;
pathDim[nLevel] = 1;
path[nLevel].push_back(current_node);
return;
}
l[current_node] = l[hn];
pathDim[l[current_node]] ++;
path[l[current_node]].push_back(current_node);
for(int i=0; i<arcs[current_node].size(); ++i) {
next_node = arcs[current_node][i];
if (next_node != hn && level[current_node] <= level[next_node]) {
pathF[l[next_node]] = current_node;
pathLevel[l[next_node]] = level[current_node];
}
}
}
void build_aint(int current_node, int left, int right, int start, int current_path) {
if (left == right) {
aint[current_node + start] = nodeValues[path[current_path][left - 1]];
return;
}
int med = (left + right) / 2;
build_aint(current_node * 2, left, med, start, current_path);
build_aint(current_node * 2 + 1, med+1, right, start, current_path);
if (aint[current_node * 2 + start] > aint[current_node * 2 + 1 + start])
aint[current_node + start] = aint[current_node * 2 + start];
else
aint[current_node + start] = aint[current_node * 2 + start + 1];
}
void updateValue(int current_node, int left, int right, int poz, int val, int start) {
if(left == right) {
aint[current_node + start] = val;
return;
}
int med = (left + right) / 2;
if (poz <= med)
updateValue(current_node * 2, left, med, poz, val, start);
else
updateValue(current_node * 2 + 1, med + 1, right, poz, val, start);
if (aint[current_node * 2 + start] > aint[current_node * 2 + 1 + start])
aint[current_node + start] = aint[current_node * 2 + start];
else
aint[current_node + start] = aint[current_node * 2 + start + 1];
}
int query(int current_node, int left, int right, int qLeft, int qRight, int start) {
if (qLeft <= left && right <= qRight)
return aint[current_node + start];
int med = (left + right) / 2, rez1 = -1, rez2 = -1;
if(qLeft <= med)
rez1 = query(current_node * 2, left, med, qLeft, qRight, start);
if(med < qRight)
rez2 = query(current_node * 2 + 1, med+1, right, qLeft, qRight, start);
if (rez1 > rez2)
return rez1;
return rez2;
}
int getMax(int x, int y) {
int sol = 0, newSol, aux;
while (1) {
if (l[x] == l[y]) {
if(level[x] > level[y]) {
aux = y;
y = x;
x = aux;
}
newSol = query(1, 1, pathDim[l[x]], level[x] - pathLevel[l[x]], level[y] - pathLevel[l[x]], pathPos[l[x]]);
if (newSol > sol)
sol = newSol;
break;
} else {
if (pathLevel[l[x]] < pathLevel[l[y]]) {
aux = x;
x = y;
y = aux;
}
newSol = query(1, 1, pathDim[l[x]], 1, level[x] - pathLevel[l[x]], pathPos[l[x]]);
if (newSol > sol)
sol = newSol;
x = pathF[l[x]];
}
}
return sol;
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int m, x, y, t;
scanf("%d%d", &n, &m);
for(int i=1; i<=n; ++i)
scanf("%d", &nodeValues[i]);
for(int i=1; i<n; ++i) {
scanf("%d%d", &x, &y);
arcs[x].push_back(y);
arcs[y].push_back(x);
}
level[1] = 1;
dfs(1);
for(int i=1; i<= nLevel; ++i) {
reverse(path[i].begin(), path[i].end());
if(i > 1)
pathPos[i] = pathPos[i-1] + pathDim[i-1] * 4;
build_aint(1, 1, pathDim[i], pathPos[i], i);
}
for(int i=1; i<=m; ++i) {
scanf("%d%d%d", &t, &x, &y);
if (t == 0)
updateValue(1, 1, pathDim[l[x]], level[x] - pathLevel[l[x]], y, pathPos[l[x]]);
else
printf("%d\n", getMax(x, y));
}
return 0;
}