#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
using namespace std;
ifstream in ("heavypath.in");
ofstream out ("heavypath.out");
const int MAXN = 100010;
vector <int> Graf[MAXN];
int subTree[MAXN];
bool Viz[MAXN];
int Lvl[MAXN];
int V[MAXN];
void DFS (int nod)
{
Viz[nod] = 1;
subTree[nod] = 1;
vector <int> :: iterator it;
for (it = Graf[nod].begin (); it != Graf[nod].end (); ++ it)
if (!Viz[*it]){
Lvl[*it] = Lvl[nod] + 1;
DFS (*it);
subTree[nod] += subTree[*it];
}
}
int nrLant;
int careLant[MAXN], lungLant[MAXN], tataLant[MAXN];
int incLant[MAXN], pozNod[MAXN];
vector <int> AINT[MAXN];
void DFS2 (int nod, int lant)
{
++ lungLant[lant];
careLant[nod] = lant;
pozNod[nod] = lungLant[lant];
Viz[nod] = 1;
vector <int> :: iterator it;
int bestSub = 0;
for (it = Graf[nod].begin (); it != Graf[nod].end (); ++ it)
if (!Viz[*it])
if (subTree[*it] > bestSub)
bestSub = subTree[*it];
for (it = Graf[nod].begin (); it != Graf[nod].end (); ++ it)
if (!Viz[*it] && subTree[*it] == bestSub){
DFS2 (*it, lant);
break;
}
for (it = Graf[nod].begin (); it != Graf[nod].end (); ++ it)
if (!Viz[*it]){
++ nrLant;
incLant[nrLant] = *it;
tataLant[nrLant] = nod;
DFS2 (*it, nrLant);
}
}
void update (int lant, int nod, int st, int dr, int poz, int val)
{
if (st == dr){
AINT[lant][nod] = val;
return;
}
int mid = (st + dr) / 2;
if (poz <= mid)
update (lant, nod * 2, st, mid, poz, val);
else
update (lant, nod * 2 + 1, mid + 1, dr, poz, val);
AINT[lant][nod] = max (AINT[lant][2 * nod], AINT[lant][2 * nod + 1]);
}
int query (int lant, int nod, int st, int dr, int A, int B)
{
if (A > B)
swap (A, B);
if (A <= st && dr <= B)
return AINT[lant][nod];
int mid = (st + dr) / 2;
int Ans = 0;
if (A <= mid)
Ans = max (Ans, query (lant, nod * 2, st, mid, A, B));
if (mid < B)
Ans = max (Ans, query (lant, nod * 2 + 1, mid + 1, dr, A, B));
return Ans;
}
int Solve (int X, int Y)
{
int Ans = 0;
while (careLant[X] != careLant[Y]){
if (Lvl[incLant[careLant[X]]] < Lvl[incLant[careLant[Y]]])
swap (X, Y);
Ans = max (Ans, query (careLant[X], 1, 1, lungLant[careLant[X]], 1, pozNod[X]));
X = tataLant[careLant[X]];
}
Ans = max (Ans, query (careLant[X], 1, 1, lungLant[careLant[X]], pozNod[X], pozNod[Y]));
return Ans;
}
int main()
{
int N, M, i, op, a, b;
in >> N >> M;
for (i = 1; i <= N; i ++)
in >> V[i];
for (i = 1; i < N; i ++){
in >> a >> b;
Graf[a].push_back (b);
Graf[b].push_back (a);
}
DFS (1);
memset (Viz, 0, sizeof (Viz));
incLant[++ nrLant] = 1;
DFS2 (1, 1);
for (i = 1; i <= nrLant; i ++)
AINT[i].resize (4 * lungLant[i]);
for (i = 1; i <= N; i ++)
update (careLant[i], 1, 1, lungLant[careLant[i]], pozNod[i], V[i]);
for (i = 1; i <= M; i ++){
in >> op >> a >> b;
if (op == 0){
update (careLant[a], 1, 1, lungLant[careLant[a]], pozNod[a], b);
}
else{
out << Solve (a, b) << "\n";
}
}
return 0;
}