#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
int N, M, type, x, y;
int sol, nL;
int value[100001];
int aint[400004];
int nrNod[100001], lvl[100001], l[100001], lFather[100001], lLvl[100001], lDim[100001], lPos[100001];
vector<int> V[100001], path[100001];
bool used[100001];
void dfs(int nod)
{
used[nod] = true;
nrNod[nod] = 1;
int lastNod = -1, leaf = 1;
for (vector<int>::iterator it = V[nod].begin(); it != V[nod].end(); ++it)
{
if (!used[*it])
{
leaf = 0;
lvl[*it] = lvl[nod] + 1;
dfs(*it);
nrNod[nod] += nrNod[*it];
if (lastNod == -1)
lastNod = *it;
else if (nrNod[lastNod] < nrNod[*it])
lastNod = *it;
}
}
if (leaf)
{
++nL;
l[nod] = nL;
lDim[nL] = 1;
path[nL].push_back(nod);
return;
}
l[nod] = l[lastNod];
++lDim[l[lastNod]];
path[l[lastNod]].push_back(nod);
for (vector<int>::iterator it = V[nod].begin(); it != V[nod].end(); ++it)
{
if (*it == lastNod || lvl[*it] < lvl[nod])
continue;
lFather[l[*it]] = nod;
lLvl[l[*it]] = lvl[nod];
}
}
void build(int nod, int lt, int rt, int decalaj, int lant)
{
if (lt == rt)
{
aint[nod + decalaj] = value[path[lant][lt - 1]];
return;
}
int mid = (lt + rt) >> 1;
build(nod * 2, lt, mid, decalaj, lant);
build(nod * 2 + 1, mid + 1, rt, decalaj, lant);
aint[nod + decalaj] = max(aint[nod * 2 + decalaj], aint[nod * 2 + 1 + decalaj]);
}
void make_paths()
{
lvl[1] = 1;
dfs(1);
for(int i = 1; i <= nL; ++i)
{
reverse(path[i].begin(), path[i].end());
if(i > 1)
lPos[i] = lPos[i-1] + lDim[i-1] * 4;
build(1, 1, lDim[i], lPos[i], i);
}
}
void update(int nod, int lt, int rt, int pos, int val, int decalaj)
{
if (lt == rt)
{
aint[nod + decalaj] = val;
return;
}
int mid = (lt + rt) >> 1;
if (pos <= mid)
update(nod * 2, lt, mid, pos, val, decalaj);
else
update(nod * 2 + 1, mid + 1, rt, pos, val, decalaj);
aint[nod + decalaj] = max(aint[nod * 2 + decalaj], aint[nod * 2 + 1 + decalaj]);
}
int query(int nod, int lt, int rt, int start, int finish, int decalaj)
{
if (start <= lt && rt <= finish)
return aint[nod + decalaj];
int mid = (lt + rt) >> 1, maxim = 0;;
if (start <= mid)
maxim = max(maxim, query(nod * 2, lt, mid, start, finish, decalaj));
if (mid < finish)
maxim = max(maxim, query(nod * 2 + 1, mid + 1, rt, start, finish, decalaj));
return maxim;
}
void solve()
{
for (int i = 1; i <= M; ++i)
{
fin >> type >> x >> y;
if (type == 0)
update(1, 1, lDim[l[x]], lvl[x] - lLvl[l[x]], y, lPos[l[x]]);
else
{
sol = 0;
bool ok = true;
while(ok)
{
if (l[x] == l[y])
{
if (lvl[x] > lvl[y])
swap(x, y);
sol = max(sol, query(1, 1, lDim[l[x]], lvl[x] - lLvl[l[x]], lvl[y] - lLvl[l[y]], lPos[l[x]]));
ok = false;
break;
}
if (lLvl[l[x]] < lLvl[l[y]])
swap(x, y);
sol = max(sol, query(1, 1, lDim[l[x]], 1, lvl[x] - lLvl[l[x]], lPos[l[x]]));
x = lFather[l[x]];
}
fout << sol << '\n';
}
}
}
int main()
{
fin >> N >> M;
for (int i = 1; i <= N; ++i)
fin >> value[i];
for (int i = 1, nod1, nod2; i <= N - 1; ++i)
{
fin >> nod1 >> nod2;
V[nod1].push_back(nod2);
V[nod2].push_back(nod1);
}
make_paths();
solve();
fin.close();
fout.close();
return 0;
}