#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
ifstream in("heavypath.in");
ofstream out("heavypath.out");
int n;
vector<int> vecini[MAXN];
int v[MAXN];
void citire(int &m)
{
in >> n >> m;
for (int i = 1;i <= n;++i)
in >> v[i];
for (int i = 1;i < n;++i)
{
int x,y;
in >> x >> y;
vecini[x].push_back(y);
vecini[y].push_back(x);
}
}
bool vizitat[MAXN];
int nivel[MAXN];
int nrsubarbore[MAXN];
int idlant[MAXN];
int nrlanturi;
vector<int> lant[MAXN];
int lanttata[MAXN];
int nivellant[MAXN];
int pozlant[MAXN];
int vallant[4 * MAXN];
void dfs(int nod)
{
vizitat[nod] = true;
nrsubarbore[nod] = 1;
int fiu_cu_subarbore_maxim = -1;
for (unsigned int i = 0;i < vecini[nod].size();++i)
{
int vecin = vecini[nod][i];
if (vizitat[vecin])
continue;
nivel[vecin] = nivel[nod] + 1;
dfs(vecin);
nrsubarbore[nod] += nrsubarbore[vecin];
if(fiu_cu_subarbore_maxim == -1)
fiu_cu_subarbore_maxim = vecin;
else if(nrsubarbore[vecin] > nrsubarbore[fiu_cu_subarbore_maxim])
fiu_cu_subarbore_maxim = vecin;
}
if(fiu_cu_subarbore_maxim == -1)//frunza
{
++nrlanturi;
idlant[nod] = nrlanturi;
lant[nrlanturi].push_back(nod);
return;
}
idlant[nod] = idlant[fiu_cu_subarbore_maxim];
lant[idlant[nod]].push_back(nod);
for (unsigned int i = 0;i < vecini[nod].size();++i)
{
int vecin = vecini[nod][i];
if (vecin == fiu_cu_subarbore_maxim || nivel[vecin] < nivel[nod])
continue;
lanttata[idlant[vecin]] = nod;
nivellant[idlant[vecin]] = nivel[nod];
}
}
void construire(int nod, int st, int dr, int decalaj, int id)
{
if (st == dr)
{
vallant[nod + decalaj] = v[ lant[id][st - 1] ];
return;
}
int mij = (st + dr) / 2;
construire(2 * nod, st, mij, decalaj, id);
construire(2 * nod + 1, mij + 1, dr, decalaj, id);
vallant[nod + decalaj] = max(vallant[nod * 2 + decalaj], vallant[nod * 2 + 1 + decalaj]);
}
void construire_drumuri()
{
nivel[1] = 1;
dfs(1);
for (int i = 1;i <= nrlanturi;++i)
{
reverse(lant[i].begin(), lant[i].end());//dorim parcurgere de jos in sus
if(i > 1)
pozlant[i] = pozlant[i - 1] + lant[i].size() * 4;
construire(1, 1, lant[i].size(), pozlant[i], i);
}
}
void actualizare(int nod, int st, int dr, int poz, int val, int decalaj)
{
if (st == dr)
{
vallant[nod + decalaj] = val;
return;
}
int mij = (st + dr) / 2;
if (poz <= mij)
actualizare(2 * nod, st, mij, poz, val, decalaj);
else actualizare(2 * nod + 1, mij + 1, dr, poz, val, decalaj);
vallant[nod + decalaj] = max(vallant[nod * 2 + decalaj], vallant[nod * 2 + 1 + decalaj]);
}
//sti - stanga interogarii dri - dreapta interogarii
int interogare(int nod, int st, int dr, int sti, int dri, int decalaj)
{
if (sti <= st && dr <= dri)
return vallant[nod + decalaj];
int mij = (st + dr) / 2;
int rasp = 0;
if (sti <= mij)
{
int nr = interogare(2 * nod, st, mij, sti, dri, decalaj);
if (nr > rasp)
rasp = nr;
}
if (mij + 1 <= dri)
{
int nr = interogare(2 * nod + 1, mij + 1, dr, sti, dri, decalaj);
if (nr > rasp)
rasp = nr;
}
return rasp;
}
int interogare(int x, int y)
{
int rasp = 0;
while(true)
{
if (idlant[x] == idlant[y])
{
if (nivel[x] > nivel[y])
swap(x, y);
int nr = interogare(1, 1, lant[idlant[x]].size(), nivel[x] - nivellant[idlant[x]], nivel[y] - nivellant[idlant[y]], pozlant[idlant[x]]);
if (nr > rasp)
rasp = nr;
break;
}
if (nivellant[idlant[x]] < nivellant[idlant[y]])
swap(x,y);
int nr = interogare(1, 1, lant[idlant[x]].size(), 1, nivel[x] - nivellant[idlant[x]], pozlant[idlant[x]]);
if (nr > rasp)
rasp = nr;
x = lanttata[idlant[x]];
}
return rasp;
}
int main()
{
int m;
citire(m);
construire_drumuri();
while(m > 0)
{
int t,x,y;
in >> t >> x >> y;
if (t == 0)//actualizare
actualizare(1, 1, lant[idlant[x]].size(), nivel[x] - nivellant[idlant[x]], y, pozlant[idlant[x]] );
else out << interogare(x,y) << '\n';
--m;
}
return 0;
}