#include <fstream>
#include <vector>
using namespace std;
ifstream fin ("heavypath.in");
ofstream fout("heavypath.out");
const int dim = 100002;
vector <int> a[dim];
int w[dim], h[dim], dad[dim], hh[dim], pos[dim], pos2[dim], k, aint[4 * dim], val[dim], n;
void dfs1 (int x, int tata = 0)
{
dad[x] = tata;
w[x] = 1;
h[x] = h[tata] + 1;
for (int y : a[x])
if (y != tata)
{
dfs1 (y, x);
w[x] += w[y];
}
}
void dfs2 (int x)
{
pos[x] = ++k;
pos2[k] = x;
int maxi = 0, ind = 0;
for (int y : a[x])
if (y != dad[x] && w[y] > maxi)
{
maxi = w[y];
ind = y;
}
if (ind == 0)
return;
hh[ind] = hh[x];
dfs2 (ind);
for (int y : a[x])
if (y != dad[x] && y != ind)
{
hh[y] = y;
dfs2(y);
}
}
void build (int nod, int st, int dr)
{
if (st == dr)
aint[nod] = val[pos2[st]];
else {
int mij = (st + dr)/2;
build (2 * nod, st, mij);
build (2 * nod + 1, mij + 1, dr);
aint[nod] = max(aint[2*nod], aint[2*nod+1]);
}
}
void update (int nod, int st, int dr, int poz, int value)
{
if (st == dr)
aint[nod] = value;
else {
int mij = (st + dr)/2;
if (poz <= mij)
update (2 * nod, st, mij, poz, value);
else
update (2 * nod + 1, mij + 1, dr, poz, value);
aint[nod] = max(aint[2*nod], aint[2*nod+1]);
}
}
int query (int nod, int st, int dr, int l, int r)
{
if (dr < l || r < st)
return 0;
if (l <= st && dr <= r)
return aint[nod];
else {
int mij = (st + dr)/2;
return max(query(2*nod, st, mij, l, r), query(2*nod+1, mij+1, dr, l, r));
}
}
int Query_heavy (int x, int y)
{
if (hh[x] == hh[y])
return query(1, 1, n, min(pos[x], pos[y]), max(pos[x], pos[y]));
if (h[hh[x]] < h[hh[y]])
swap (x, y);
int t = query (1, 1, n, pos[hh[x]], pos[x]);
x = dad[hh[x]];
return max(t, Query_heavy(x, y));
}
int main()
{
int q, tip, x, y;
fin >> n >> q;
for (int i = 1; i <= n; i++)
fin >> val[i];
for (int i = 1; i < n; i++)
{
fin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
dfs1 (1);
hh[1] = 1;
dfs2 (1);
build (1, 1, n);
while (q--)
{
fin >> tip >> x >> y;
if (tip == 0)
update(1, 1, n, pos[x], y);
else
fout << Query_heavy (x, y) << '\n';
}
}