#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int LOGN = 16;
const int NMAX = 100000;
int n, m, euler_idx;
int val[NMAX + 5], first_ap[NMAX + 5], h[NMAX + 5];
int path[NMAX + 5], path_poz[NMAX + 5];
int rmq[LOGN][2 * NMAX + 5];
vector<int> arb[NMAX + 5], path_dad;
vector<vector<int>> paths, aints;
void dfs(int nod, int dad) {
h[nod] = h[dad] + 1;
first_ap[nod] = ++euler_idx;
rmq[0][euler_idx] = nod;
for(int vec: arb[nod])
if(vec != dad) {
dfs(vec, nod);
rmq[0][++euler_idx] = nod;
}
}
int get_log2(int x) {
int log2 = 0;
while(x > 1) x >>= 1, log2++;
return log2;
}
void calc_rmq() {
euler_idx = 0;
dfs(1, 0);
for(int l = 2; l <= euler_idx; l *= 2)
for(int i = 1; i + l - 1 <= euler_idx; i++) {
int log2 = get_log2(l), nod_st = rmq[log2 - 1][i], nod_dr = rmq[log2 - 1][i + l / 2];
rmq[log2][i] = (h[nod_st] < h[nod_dr]) ? nod_st : nod_dr;
}
}
int get_lca(int nod1, int nod2) {
int f1 = first_ap[nod1], f2 = first_ap[nod2];
if(f1 > f2) swap(f1, f2);
int l = f2 - f1 + 1, log2 = get_log2(l);
int nst = rmq[log2][f1], ndr = rmq[log2][f2 - l + 1];
return (h[nst] < h[ndr]) ? nst : ndr;
}
int path_decomposition(int nod, int dad) {
bool frunza = true;
int path_length = 0, heaviest = -1;
for(int vec: arb[nod])
if(vec != dad) {
frunza = false;
int vec_length = path_decomposition(vec, nod);
if(vec_length + 1 > path_length) {
path_length = vec_length + 1;
heaviest = path[vec];
}
}
if(!frunza) {
paths[heaviest].push_back(nod);
path[nod] = heaviest;
path_poz[nod] = paths[heaviest].size() - 1;
for(int vec: arb[nod])
if(vec != dad && path[vec] != heaviest)
path_dad[path[vec]] = nod;
}
else {
vector<int> new_path;
paths.push_back(new_path);
paths.back().push_back(nod);
path_dad.push_back(0);
path[nod] = paths.size() - 1;
path_poz[nod] = 0;
}
return path_length;
}
void update(vector<int> &aint, int nod, int nst, int ndr, int upoz, int val) {
if(nst > ndr || upoz < nst || upoz > ndr) return;
if(nst == ndr) {
aint[nod] = val;
return;
}
int mij = (nst + ndr) / 2;
if(upoz <= mij)
update(aint, 2 * nod, nst, mij, upoz, val);
else
update(aint, 2 * nod + 1, mij + 1, ndr, upoz, val);
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
int qaint(vector<int> &aint, int nod, int nst, int ndr, int qst, int qdr) {
if(nst > ndr || qst > ndr || qdr < nst) return 0;
if(nst >= qst && ndr <= qdr) return aint[nod];
int mij = (nst + ndr) / 2;
int q1 = qaint(aint, 2 * nod, nst, mij, qst, qdr);
int q2 = qaint(aint, 2 * nod + 1, mij + 1, ndr, qst, qdr);
return max(q1, q2);
}
int query(int nod1, int nod2) {
int ans = 0, lca = get_lca(nod1, nod2);
while(path[nod1] != path[lca]) {
int p = path[nod1], psz = paths[p].size();
ans = max(ans, qaint(aints[p], 1, 0, psz - 1, path_poz[nod1], psz - 1));
nod1 = path_dad[p];
}
while(path[nod2] != path[lca]) {
int p = path[nod2], psz = paths[p].size();
ans = max(ans, qaint(aints[p], 1, 0, psz - 1, path_poz[nod2], psz - 1));
nod2 = path_dad[p];
}
int p = path[lca], poz1 = path_poz[nod1], poz2 = path_poz[nod2];
if(poz1 > poz2) swap(poz1, poz2);
ans = max(ans, qaint(aints[p], 1, 0, paths[p].size() - 1, poz1, poz2));
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);
}
calc_rmq();
path_decomposition(1, 0);
for(int i = 0; i < paths.size(); i++) {
vector<int> new_aint;
aints.push_back(new_aint);
aints[i].resize(4 * paths[i].size(), 0);
for(int j = 0; j < paths[i].size(); j++)
update(aints[i], 1, 0, paths[i].size() - 1, j, val[paths[i][j]]);
}
for(int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d %d %d", &t, &x, &y);
if(t == 0)
update(aints[path[x]], 1, 0, paths[path[x]].size() - 1, path_poz[x], y);
else
printf("%d\n", query(x, y));
}
return 0;
}