#include <bits/stdc++.h>
using namespace std;
ifstream fi("heavypath.in");
ofstream fo("heavypath.out");
#define cin fi
#define cout fo
const int NMAX = 1e5 + 5;
int n, q;
vector <int> G[NMAX];
int v[NMAX], p[NMAX], niv[NMAX];
int subarb[NMAX];
int inCeLant[NMAX];
vector <int> noduriLant[NMAX];
int pozInLant[NMAX];
int cntLanturi;
int aint[4 * NMAX];
int decalaj[NMAX];
int st, dr, rez, poz, val;
inline void bagaInLant(int nod, int lant)
{
inCeLant[nod] = lant;
noduriLant[lant].push_back(nod);
}
void getLant(int nod)
{
for (auto v: G[nod])
{
if (v != p[nod])
{
p[v] = nod;
niv[v] = niv[nod] + 1;
getLant(v);
subarb[nod] += subarb[v];
}
}
if ((G[nod].size() == 1 && nod != 1) || (nod == 1 && n == 1)) // frunza
{
subarb[nod] = 1;
cntLanturi++;
bagaInLant(nod, cntLanturi);
return;
}
int maxim = 0, unde = 0;
for (auto v: G[nod])
if (v != p[nod] && subarb[v] > maxim)
maxim = subarb[v], unde = v;
bagaInLant(nod, inCeLant[unde]);
}
void build(int lant, int nod, int l, int r)
{
if (l == r)
{
aint[nod + decalaj[lant]] = v[noduriLant[lant][l]];
return;
}
int mij = (l + r) / 2;
build(lant, 2 * nod, l, mij);
build(lant, 2 * nod + 1, mij + 1, r);
aint[nod + decalaj[lant]] = max(aint[2 * nod + decalaj[lant]], aint[2 * nod + 1 + decalaj[lant]]);
}
void update(int lant, int nod, int l, int r)
{
if (l == r)
{
aint[nod + decalaj[lant]] = val;
return;
}
int mij = (l + r) / 2;
if (poz <= mij)
update(lant, 2 * nod, l, mij);
else
update(lant, 2 * nod + 1, mij + 1, r);
aint[nod + decalaj[lant]] = max(aint[2 * nod + decalaj[lant]], aint[2 * nod + 1 + decalaj[lant]]);
}
void query(int lant, int nod, int l, int r)
{
if (st <= l && r <= dr)
{
rez = max(rez, aint[nod + decalaj[lant]]);
return;
}
int mij = (l + r) / 2;
if (st <= mij)
query(lant, 2 * nod, l, mij);
if (dr > mij)
query(lant, 2 * nod + 1, mij + 1, r);
}
int main()
{
cin >> n >> q;
for (int i = 1; i <= n; i++)
cin >> v[i];
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
getLant(1);
for (int i = 1; i <= cntLanturi; i++)
{
reverse(noduriLant[i].begin(), noduriLant[i].end());
decalaj[i] = decalaj[i - 1] + 4 * noduriLant[i - 1].size();
}
for (int i = 1; i <= cntLanturi; i++)
for (int j = 0; j < noduriLant[i].size(); j++)
pozInLant[noduriLant[i][j]] = j;
for (int i = 1; i <= cntLanturi; i++)
build(i, 1, 0, noduriLant[i].size() - 1);
while (q--)
{
int t, x, y;
cin >> t >> x >> y;
if (t == 0)
{
// update: v[x] = y
poz = pozInLant[x], val = y;
update(inCeLant[x], 1, 0, noduriLant[inCeLant[x]].size() - 1);
}
else
{
// query: maxim pe x...y
// il tin pe x mai jos
int ansQuery = -1;
while (inCeLant[x] != inCeLant[y])
{
int px = noduriLant[inCeLant[x]][0], py = noduriLant[inCeLant[y]][0];
if (niv[px] < niv[py])
swap(x, y), swap(px, py);
rez = 0;
st = 0;
dr = pozInLant[x];
query(inCeLant[x], 1, 0, noduriLant[inCeLant[x]].size() - 1);
ansQuery = max(ansQuery, rez);
x = p[px];
}
// sunt pe acelasi lant
rez = 0;
st = min(pozInLant[x], pozInLant[y]);
dr = max(pozInLant[x], pozInLant[y]);
query(inCeLant[y], 1, 0, noduriLant[inCeLant[y]].size() - 1);
ansQuery = max(ansQuery, rez);
cout << ansQuery << "\n";
}
}
return 0;
}