#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <string.h>
using namespace std;
#define NMAX 100001
vector <int> v[NMAX];
vector <int> path[NMAX];
vector <int> arb[NMAX];
int value[NMAX], viz[NMAX], w[NMAX], niv[NMAX], p[NMAX], poz[NMAX], parent[NMAX], whatpoz[NMAX], nr_paths, q_sol;
int dfs(int nod, int lev) {
int frunza = 1, crt = 0, fiu, sum = 0;
viz[nod] = 1;
niv[nod] = lev;
for (vector <int> :: iterator it = v[nod].begin(); it != v[nod].end(); it++)
if (viz[*it] == 0) {
p[*it] = nod;
int w = dfs(*it, lev + 1);
frunza = 0;
if (w > crt) {
crt = w;
fiu = *it;
}
sum = sum + w;
}
if (frunza) {
nr_paths++;
path[nr_paths].push_back(nod);
poz[nod] = nr_paths;
}
else {
path[poz[fiu]].push_back(nod);
poz[nod] = poz[fiu];
}
return sum + 1;
}
void build(int nod, int st, int dr, int index) {
int mij;
if (st == dr) {
arb[index][nod] = value[path[index][st]];
return ;
}
mij = (st + dr) / 2;
build(nod * 2, st, mij, index);
build(nod * 2 + 1, mij + 1, dr, index);
arb[index][nod] = max(arb[index][2 * nod], arb[index][2 * nod + 1]);
}
void update(int nod, int st, int dr, int poz, int val, int index) {
if (st == dr) {
arb[index][nod] = val;
return ;
}
int mij = (st + dr) / 2;
if (poz <= mij)
update(nod * 2, st, mij, poz, val, index);
else
update(nod * 2 + 1, mij + 1, dr, poz, val, index);
arb[index][nod] = max(arb[index][2 * nod], arb[index][2 * nod + 1]);
}
void query(int nod, int st, int dr, int aa, int bb, int index) {
if (aa <= st && dr <= bb) {
q_sol = max(q_sol, arb[index][nod]);
return ;
}
int mij = (st + dr) / 2;
if (aa <= mij)
query(nod * 2, st, mij, aa, bb, index);
if (mij < bb)
query(nod * 2 + 1, mij + 1, dr, aa, bb, index);
}
void make_paths() {
int i;
for (i = 1; i <= nr_paths; i++) {
reverse(path[i].begin(), path[i].end());
for (vector <int> :: iterator it = path[i].begin(); it != path[i].end(); it++) {
whatpoz[*it] = it - path[i].begin();
}
arb[i].resize(4 * path[i].size() + 1);
build(1, 0, path[i].size() - 1, i);
parent[i] = p[*path[i].begin()];
}
}
int which(int x, int y) {
if (poz[x] == poz[y]) {
if (niv[y] < niv[x])
swap(x, y);
q_sol = -1;
query(1, 0, path[poz[x]].size() - 1, whatpoz[x], whatpoz[y], poz[x]);
return q_sol;
}
int px = parent[poz[x]];
int py = parent[poz[y]];
if (niv[py] > niv[px] || (niv[py] == niv[px] && px == 0)) {
swap(x, y);
swap(px, py);
}
q_sol = -1;
query(1, 0, path[poz[x]].size() - 1, 0, whatpoz[x], poz[x]);
int sol = q_sol;
return max(sol, which(px, y));
}
int main()
{
int n, m, x, y, i, opt;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
f >> n >> m;
for (i = 1; i <= n; i++)
f >> value[i];
for (i = 1; i <= n - 1; i++) {
f >> x >> y;
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1, 0);
make_paths();
for (i = 1; i <= m; i++) {
f >> opt >> x >> y;
if (opt == 0) {
update(1, 0, path[poz[x]].size() - 1, whatpoz[x], y, poz[x]);
}
else {
g << which(x, y) << '\n';
}
}
return 0;
}