#include <bits/stdc++.h>
using namespace std;
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
const int MaxN = 1e5 + 5;
int n, m;
int val[MaxN], sz[MaxN], what_lant[MaxN], nr_lant, poz_lant[MaxN], niv[MaxN], tata_lant[MaxN];
vector <int> elem_lant[MaxN];
vector < int > adj[MaxN];
void DFS (int nod, int tata) {
int leaf = 1;
sz[nod] = 1;
int heavy_son = 0;
for (auto i : adj[nod])
if (i != tata) {
leaf = 0;
niv[i] = niv[nod] + 1;
DFS(i, nod);
sz[nod] += sz[i];
if (!heavy_son || sz[heavy_son] < sz[i])
heavy_son = i;
}
if (leaf) {
what_lant[nod] = ++nr_lant;
poz_lant[nod] = 1;
elem_lant[nr_lant].push_back(0);
elem_lant[nr_lant].push_back(nod);
return;
}
what_lant[nod] = what_lant[heavy_son];
elem_lant[what_lant[nod]].push_back(nod);
poz_lant[nod] = elem_lant[what_lant[nod]].size() - 1;
for (int i : adj[nod]) {
if (i != heavy_son && i != tata) {
tata_lant[what_lant[i]] = nod;
}
}
}
vector <vector <int> > aint;
void Build (int nr, int nod, int st, int dr) {
if (st == dr) {
aint[nr][nod] = val[elem_lant[nr][st]];
}
else {
int mid = (st + dr ) / 2;
Build(nr, 2 * nod, st, mid);
Build(nr, 2 * nod + 1, mid + 1, dr);
aint[nr][nod] = max (aint[nr][2 * nod], aint[nr][2 * nod + 1]);
}
}
void Update (int nr, int nod, int st, int dr, int poz, int val) {
if (st == dr && st == poz)
aint[nr][nod] = val;
else {
int mid = (st + dr) / 2;
if (poz <= mid)
Update(nr, 2 * nod, st, mid, poz , val);
else Update(nr, 2 * nod + 1, mid + 1, dr, poz, val);
aint[nr][nod] = max(aint[nr][2 * nod], aint[nr][2 * nod + 1]);
}
}
int Query (int nr, int nod, int st, int dr, int x, int y) {
if (x <= st && dr <= y) {
return aint[nr][nod];
}
else {
int mid = (st + dr) / 2;
int val1 = -2e9, val2 = -2e9;
if (x <= mid)
val1 = Query(nr, 2 * nod, st, mid, x, y);
if (y > mid)
val2 = Query (nr , 2 * nod + 1, mid + 1, dr, x, y);
return max(val1, val2);
}
}
int Solve (int x, int y) {
if (what_lant[x] == what_lant[y]) {
return Query(what_lant[x], 1, 1, elem_lant[what_lant[x]].size() - 1, min(poz_lant[y], poz_lant[x]), max(poz_lant[y], poz_lant[x]));
}
if (niv[tata_lant[what_lant[x]]] < niv[tata_lant[what_lant[y]]])
swap(x, y);
int val1 = Query(what_lant[x], 1, 1, elem_lant[what_lant[x]].size() - 1, 1, poz_lant[x]);
int val2 = Solve(tata_lant[what_lant[x]], y);
return max (val1, val2);
}
int main()
{
fin >> n >> m;
for (int i = 1; i <= n; i++)
fin >> val[i];
for (int i = 1; i < n; i++){
int x , y;
fin >> x >> y;
adj[x].push_back(y);
adj[y].push_back(x);
}
tata_lant[1] = 0;
nr_lant = 1;
DFS(1, 0);
aint.resize(nr_lant * 4);
for (int i = 1; i <= nr_lant; i++) {
aint[i].resize(30);
reverse(elem_lant[i].begin() + 1, elem_lant[i].end());
Build(i, 1, 1, elem_lant[i].size() - 1);
}
for (int i = 1; i <= n; i++)
poz_lant[i] = elem_lant[what_lant[i]].size() - poz_lant[i];
for (int i = 1; i <= m; i++) {
int x, y, t;
fin >> t >> x >> y;
if (t == 0)
Update(what_lant[x], 1, 1, elem_lant[what_lant[x]].size() - 1, poz_lant[x], y);
else {
int ans = Solve(x, y);
fout << ans << "\n";
}
}
return 0;
}