#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int NMAX = 100000;
int n, m, euler_idx, cnt_paths;
int val[NMAX + 5], euler[2 * NMAX + 5], first_ap[NMAX + 5], h[NMAX + 5];
int path_first[NMAX + 5], path[NMAX + 5], aint[8 * NMAX + 5];
vector<int> arb[NMAX + 5];
int dfs(int nod, int dad) {
int max_fii = 0, nrfii = 1;
h[nod] = h[dad] + 1;
for(int i = 0; i < arb[nod].size(); i++)
if(arb[nod][i] != dad) {
int fii_vec = dfs(arb[nod][i], nod);
nrfii += fii_vec;
if(fii_vec > max_fii) {
swap(arb[nod][0], arb[nod][i]);
max_fii = fii_vec;
}
}
return nrfii;
}
void euler_tour(int nod, int dad) {
euler[++euler_idx] = nod;
first_ap[nod] = euler_idx;
for(int vec: arb[nod])
if(vec != dad) {
euler_tour(vec, nod);
euler[++euler_idx] = nod;
}
}
void path_decomposition() {
for(int i = 1; i <= 2 * n - 1; i++) {
if(h[euler[i]] - 1 != h[euler[i - 1]]) /// euler[i] face parte deja dintr-un lant
continue;
if(i == 1 || h[euler[i - 1]] - 1 != h[euler[i - 2]]) { /// euler[i] este tatal unui nou lant
path[euler[i]] = ++cnt_paths;
path_first[euler[i]] = euler[i];
}
else { /// sunt in interiorul unui lant
path[euler[i]] = path[euler[i - 1]];
path_first[euler[i]] = path_first[euler[i - 1]];
}
}
}
void init(int nod, int nst, int ndr) {
if(nst == ndr)
aint[nod] = euler[nst];
else {
int mij = (nst + ndr) / 2;
init(2 * nod, nst, mij);
init(2 * nod + 1, mij + 1, ndr);
aint[nod] = (val[aint[2 * nod]] > val[aint[2 * nod + 1]]) ? aint[2 * nod] : aint[2 * nod + 1];
}
}
void update(int nod, int nst, int ndr, int poz) {
if(nst == ndr)
return;
int mij = (nst + ndr) / 2;
if(poz <= mij) update(2 * nod, nst, mij, poz);
else update(2 * nod + 1, mij + 1, ndr, poz);
aint[nod] = (val[aint[2 * nod]] > val[aint[2 * nod + 1]]) ? aint[2 * nod] : aint[2 * nod + 1];
}
int query(int nod, int nst, int ndr, int qst, int qdr) {
if(ndr < qst || nst > qdr) return 0;
if(nst >= qst && ndr <= qdr) return val[aint[nod]];
int mij = (nst + ndr) / 2;
return max(query(2 * nod, nst, mij, qst, qdr), query(2 * nod + 1, mij + 1, ndr, qst, qdr));
}
int query(int nod1, int nod2) {
int ans = 0;
while(path[nod1] != path[nod2])
if(h[path_first[nod1]] > h[path_first[nod2]]) {
ans = max(ans, query(1, 1, 2 * n - 1, first_ap[path_first[nod1]], first_ap[nod1]));
nod1 = euler[first_ap[euler[first_ap[path_first[nod1]] - 1]]];
}
else {
ans = max(ans, query(1, 1, 2 * n - 1, first_ap[path_first[nod2]], first_ap[nod2]));
nod2 = euler[first_ap[euler[first_ap[path_first[nod2]] - 1]]];
}
if(first_ap[nod1] > first_ap[nod2]) swap(nod1, nod2);
ans = max(ans, query(1, 1, 2 * n - 1, first_ap[nod1], first_ap[nod2]));
return ans;
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &val[i]);
for(int i = 1; i < n; i++) {
int x, y;
scanf("%d %d", &x, &y);
arb[x].push_back(y);
arb[y].push_back(x);
}
dfs(1, 0);
euler_tour(1, 0);
path_decomposition();
init(1, 1, 2 * n - 1);
for(int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d %d %d", &t, &x, &y);
if(t == 0) {
val[x] = y;
update(1, 1, 2 * n - 1, first_ap[x]);
}
else
printf("%d\n", query(x, y));
}
return 0;
}