#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 100005;
const int oo = 0x3f3f3f3f;
int n, m, h[maxn], level[maxn], pathpos[maxn], pathfather[maxn], pathwhere[maxn], paths, v[maxn];
vector <int> g[maxn], path[maxn], arb[maxn];
inline void dfs(int node, int father) {
level[node] = level[father] + 1;
h[node] = 1;
int heaviest = -1;
for(auto it : g[node]) {
if(it == father)
continue;
dfs(it, node);
h[node] += h[it];
if(heaviest == -1)
heaviest = it;
else if(h[heaviest] < h[it])
heaviest = it;
}
if(heaviest == -1)
pathwhere[node] = ++ paths;
else
pathwhere[node] = pathwhere[heaviest];
path[pathwhere[node]].push_back(node);
pathfather[pathwhere[node]] = father;
}
const int lim = (1 << 20);
char buff[lim];
int pos;
inline void getint(int &x) {
x = 0;
while(!('0' <= buff[pos] && buff[pos] <= '9'))
if(++ pos == lim) {
pos = 0;
fread(buff, 1, lim, stdin);
}
while('0' <= buff[pos] && buff[pos] <= '9') {
x = x * 10 + buff[pos] - '0';
if(++ pos == lim) {
pos = 0;
fread(buff, 1, lim, stdin);
}
}
}
inline void build(int node, int st, int dr, int w) {
if(st == dr) {
arb[w][node] = v[path[w][st]];
return ;
}
int mid = ((st + dr) >> 1);
build(node << 1, st, mid, w);
build((node << 1) | 1, mid + 1, dr, w);
arb[w][node] = max(arb[w][node << 1], arb[w][(node << 1) | 1]);
}
inline void update(int node, int st, int dr, int pos, int value, int w) {
if(st == dr) {
arb[w][node] = w;
return ;
}
int mid = ((st + dr) >> 1);
if(pos <= mid)
update(node << 1, st, mid, pos, value, w);
else
update((node << 1) | 1, mid + 1, dr, pos, value, w);
arb[w][node] = max(arb[w][node << 1], arb[w][(node << 1) | 1]);
}
inline int query(int node, int st, int dr, int a, int b, int w) {
if(a <= st && dr <= b)
return arb[w][node];
int mid = ((st + dr) >> 1);
int ret = -oo;
if(a <= mid)
ret = max(ret, query(node << 1, st, mid, a, b, w));
if(mid < b)
ret = max(ret, query((node << 1) | 1, mid + 1, dr, a, b, w));
return ret;
}
inline int queryhpd(int x, int y) {
if(pathwhere[x] == pathwhere[y]) {
if(pathpos[x] > pathpos[y])
swap(x, y);
return query(1, 0, path[pathwhere[x]].size() - 1, pathpos[x], pathpos[y], pathwhere[x]);
}
if(level[pathfather[pathwhere[x]]] < level[pathfather[pathwhere[y]]])
swap(x, y);
return max(queryhpd(pathfather[pathwhere[x]], y), query(1, 0, path[pathwhere[x]].size() - 1, 0, pathpos[x], pathwhere[x]));
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
getint(n);
getint(m);
for(int i = 1 ; i <= n ; ++ i)
getint(v[i]);
for(int i = 1 ; i < n ; ++ i) {
int x, y;
getint(x);
getint(y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1, 0);
for(int i = 1 ; i <= paths; ++ i) {
reverse(path[i].begin(), path[i].end());
for(int j = 0 ; j < path[i].size() ; ++ j)
pathpos[path[i][j]] = j;
arb[i].resize(path[i].size() << 2);
build(1, 0, path[i].size() - 1, i);
}
for(int i = 1 ; i <= m ; ++ i) {
int op, x, y;
getint(op);
getint(x);
getint(y);
if(op == 0)
update(1, 0, path[pathwhere[x]].size() - 1, pathpos[x], y, pathwhere[x]);
else
cout << queryhpd(x, y) << '\n';
}
}