#include <cstdio>
#include <algorithm>
using namespace std;
const int Nmax = 100000;
const int Hmax = 1000; // numarul maxim de carari
const int NIL = -1;
struct Edge {
int v, next;
};
Edge l[2 * Nmax - 2]; // liste de adiacenta alocate static
int adj[Nmax]; // capete de liste
int key[Nmax]; // valorile date
int father[Nmax]; // father[u] = parintele nodului u
int depth[Nmax]; // depth[u] = adancimea nodului u
int siz[Nmax]; // siz[u] = marimea subarborelui cu radacina u
int path[Nmax]; // path[u] = cararea careia ii apartine u
int lenPath[Nmax]; // lenPath[i] = lungimea cararii i
int nPaths; // numarul total de carari
int posPath[Nmax]; // pozitia nodului u in cararea careia ii apartine
int startPath[Nmax]; // startPath[i] = nodul de start din cararea i
int T[Hmax][2 * Nmax]; // arbore de intervale pentru fiecare cale
void addEdge(int u, int v, int pos) {
l[pos].v = v;
l[pos].next = adj[u];
adj[u] = pos;
}
void dfs(int u) {
int heavySize = 0, i, v;
siz[u] = 1;
path[u] = NIL;
for (i = adj[u]; i != NIL; i = l[i].next) {
v = l[i].v;
if (father[v] == NIL) {
father[v] = u;
depth[v] = depth[u] + 1;
dfs(v);
siz[u] += siz[v];
if (heavySize < siz[v]) {
heavySize = siz[v];
path[u] = path[v];
}
}
}
if (path[u] == NIL) {
path[u] = nPaths++;
}
posPath[u] = lenPath[path[u]]++;
}
void buildHPD(int n) {
int i;
father[0] = 0;
depth[0] = 0;
dfs(0);
for (i = 0; i < n; i++) { // oglidim caile
posPath[i] = lenPath[path[i]] - posPath[i] - 1;
if (posPath[i] == 0) {
startPath[path[i]] = i;
}
}
}
void buildSegmentedTrees(int n) {
int i, j;
for (i = 0; i < n; i++) {
T[path[i]][posPath[i] + lenPath[path[i]]] = key[i];
}
for (i = 0; i < nPaths; i++) {
for (j = lenPath[i] - 1; j > 0; j--) {
T[i][j] = max(T[i][2 * j], T[i][2 * j + 1]);
}
}
}
void update(int u, int key) {
int p = path[u];
int q = posPath[u] + lenPath[p], x;
T[p][q] = key;
while (q > 1) {
x = q / 2;
T[p][x] = max(T[p][q], T[p][q ^ 1]);
q = x;
}
}
int segQuery(int path, int u, int v) {
int answer = 0;
if (u > v) {
swap(u, v);
}
u += lenPath[path];
v += lenPath[path] + 1;
while (u < v) {
if (u & 1) {
answer = max(answer, T[path][u]);
u++;
}
if (v & 1) {
v--;
answer = max(answer, T[path][v]);
}
u >>= 1;
v >>= 1;
}
return answer;
}
int query(int u, int v) {
if (depth[startPath[path[u]]] < depth[startPath[path[v]]]) {
swap(u, v);
}
if (path[u] == path[v]) {
return segQuery(path[u], posPath[u], posPath[v]);
} else { // u apartine caii celei mai adanci
return max(segQuery(path[u], 0, posPath[u]), query(father[startPath[path[u]]], v));
}
}
int main(void) {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int n, m, i;
int tip, u, v;
scanf("%d%d", &n, &m);
for (i = 0; i < n; i++) {
adj[i] = NIL;
father[i] = NIL;
scanf("%d", &key[i]);
}
for (i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
addEdge(u - 1, v - 1, 2 * i - 2);
addEdge(v - 1, u - 1, 2 * i - 1);
}
buildHPD(n);
buildSegmentedTrees(n);
for (i = 0; i < m; i++) {
scanf("%d%d%d", &tip, &u, &v);
if (tip == 0) {
update(u - 1, v);
} else {
printf("%d\n", query(u - 1, v - 1));
}
}
fclose(stdin);
fclose(stdout);
return 0;
}