#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
ifstream in("heavypath.in");
ofstream out("heavypath.out");
const int dim = 1e5 + 5;
int n, q, first[dim], nxt[dim], parent[dim], sz[dim], hp_id[dim], val[dim], rezultat, adancime[dim], poz[dim];
vector<int> vec[dim];
vector<int> liste[dim];
vector<int> liste_arb[dim];
void Construieste_arbore(int nod, int st, int dr, int care) {
if (st == dr) {
liste_arb[care][nod] = val[liste[care][st-1]];
} else {
int mid = (st + dr) / 2;
Construieste_arbore(2 * nod, st, mid, care);
Construieste_arbore(2 * nod + 1, mid + 1, dr, care);
liste_arb[care][nod] = max(liste_arb[care][2 * nod], liste_arb[care][2*nod+1]);
}
}
void Update(int nod, int st, int dr, int care, int poz, int val) {
if (st == dr) {
liste_arb[care][nod] = val;
} else {
int mid = (st + dr) / 2;
if (poz <= mid) {
Update(2 * nod, st, mid, care, poz, val);
} else {
Update(2 * nod + 1, mid+1, dr, care, poz, val);
}
liste_arb[care][nod] = max(liste_arb[care][2 * nod], liste_arb[care][2*nod+1]);
}
}
void Query(int nod, int st, int dr, int a, int b, int care) {
if (a <= st && dr <= b) {
if (a == 1 && b == 1) {
/// cout << liste_arb[care][nod];
}
rezultat = max(liste_arb[care][nod], rezultat);
} else {
int mid = (st + dr) / 2;
if (a <= mid) Query(2 * nod, st, mid, a, b, care);
if (b > mid) Query(2 * nod+1, mid+1, dr, a, b, care);
}
}
int Quer_arb(int care, int a, int b) {
rezultat = 0;
Query(1, 1, liste[care].size(), a, b, care);
return rezultat;
}
void Update_arb(int care, int poz, int val) {
Update(1, 1, liste[care].size(), care, poz, val);
}
void heavypath(int nod, int &k) {
int curent = k;
if (first[k] == 0) {
first[k] = nod;
}
hp_id[nod] = k;
liste[k].push_back(nod);
poz[nod] = liste[k].size();
for (auto &y:vec[nod]) {
if (y != parent[nod]) {
if (sz[y] > sz[nxt[nod]]) {
nxt[nod] = y;
}
}
}
if (nxt[nod] != 0) {
heavypath(nxt[nod], k);
}
for (auto &y:vec[nod]) {
if (y != parent[nod] && y != nxt[nod]) {
k++;
adancime[k] = adancime[curent] + 1;
heavypath(y, k);
}
}
}
void DFS(int nod, int par=-1) {
parent[nod] = par;
sz[nod] = 1;
for (auto &y:vec[nod]) {
if (y != par) {
DFS(y, nod);
sz[nod] += sz[y];
}
}
}
int query_mare(int x, int y) {
int rasp = 0;
while (hp_id[x] != hp_id[y]) {
if (adancime[hp_id[x]] > adancime[hp_id[y]]) {
rasp = max(rasp, Quer_arb(hp_id[x], 1, poz[x]));
x = parent[first[hp_id[x]]];
} else {
rasp = max(rasp, Quer_arb(hp_id[y], 1, poz[y]));
y = parent[first[hp_id[y]]];
}
}
rasp = max(rasp, Quer_arb(hp_id[x], min(poz[x], poz[y]), max(poz[x], poz[y])));
return rasp;
}
int main() {
in >> n >> q;
int a, b;
for (int i=1; i<=n; i++) {
in >> val[i];
}
for (int i=1; i<n; i++) {
in >> a >> b;
vec[a].push_back(b);
vec[b].push_back(a);
}
DFS(1);
int k = 0;
heavypath(1, k);
for (int i=0; i<=k; i++) {
liste_arb[i].resize(4 * liste[i].size());
Construieste_arbore(1, 1, liste[i].size(), i);
}
int op, x, y;
while (q--) {
in >> op >> x >> y;
if (op == 0) {
Update_arb(hp_id[x], poz[x], y);
} else {
out << query_mare(x, y) << "\n";
}
}
return 0;
}