#include <fstream>
#include <vector>
using namespace std;
ifstream cin ("heavypath.in");
ofstream cout ("heavypath.out");
vector <int> adiacenta[100001];
int valoare[100001] , invers[100001] , nod_sursa[100001] , reprezentant[100001] , lant[100001] , pozitie[100001] , cantitate[100002] , adancime[100001] , adaos[100001] , arbore[400000];
void Parcurgere (const int nod_actual)
{
int maxim = 0;
cantitate[nod_actual] = 1;
adancime[nod_actual] = adancime[nod_sursa[nod_actual]] + 1;
for (auto nod_vecin : adiacenta[nod_actual]) {
if (nod_vecin != nod_sursa[nod_actual])
{
nod_sursa[nod_vecin] = nod_actual;
Parcurgere(nod_vecin);
cantitate[nod_actual] += cantitate[nod_vecin];
if (cantitate[nod_vecin] > cantitate[maxim])
{ maxim = nod_vecin; }
}
}
if (!maxim)
{
lant[nod_actual] = ++lant[0];
reprezentant[lant[nod_actual]] = nod_actual;
pozitie[nod_actual] = 1;
return;
}
lant[nod_actual] = lant[maxim];
pozitie[nod_actual] = pozitie[maxim] + 1;
reprezentant[lant[nod_actual]] = nod_actual;
}
int Build (const int nod , const int stanga , const int dreapta , const int termen)
{
if (stanga == dreapta)
{ arbore[nod + termen] = valoare[invers[stanga]]; return nod + termen; }
int candidat = 0;
const int mijloc = (stanga + dreapta) >> 1;
candidat = max(candidat , Build(nod << 1 , stanga , mijloc , termen));
candidat = max(candidat , Build((nod << 1) | 1 , mijloc + 1 , dreapta , termen));
arbore[nod + termen] = max(arbore[(nod << 1) + termen] , arbore[((nod << 1) | 1) + termen]);
return candidat;
}
void Update (const int nod , const int stanga , const int dreapta , const int pozitie , const int termen)
{
if (stanga == dreapta)
{ cin >> arbore[nod + termen]; return; }
const int mijloc = (stanga + dreapta) >> 1;
if (pozitie <= mijloc) { Update(nod << 1 , stanga , mijloc , pozitie , termen); }
else { Update((nod << 1) | 1 , mijloc + 1 , dreapta , pozitie , termen); }
arbore[nod + termen] = max(arbore[(nod << 1) + termen] , arbore[((nod << 1) | 1) + termen]);
}
int Query (const int nod , const int stanga , const int dreapta , const int stanga_interval , const int dreapta_interval , const int termen)
{
if (stanga_interval <= stanga && dreapta <= dreapta_interval)
{ return arbore[nod + termen]; }
int raspuns = 0;
const int mijloc = (stanga + dreapta) >> 1;
if (stanga_interval <= mijloc) { raspuns = max(raspuns , Query(nod << 1 , stanga , mijloc , stanga_interval , dreapta_interval , termen)); }
if (dreapta_interval > mijloc) { raspuns = max(raspuns , Query((nod << 1) | 1 , mijloc + 1 , dreapta , stanga_interval , dreapta_interval , termen)); }
return raspuns;
}
int main ()
{
int numar_noduri , numar_operatii;
cin >> numar_noduri >> numar_operatii;
for (int indice = 1 ; indice <= numar_noduri ; indice++)
{ cin >> valoare[indice]; }
for (int indice = 1 , nod[2] ; indice < numar_noduri ; indice++)
{ cin >> nod[0] >> nod[1]; adiacenta[nod[0]].push_back(nod[1]); adiacenta[nod[1]].push_back(nod[0]); }
Parcurgere(1);
for (int indice = 1 ; indice <= numar_noduri ; indice++)
{ cantitate[indice] = 0; }
for (int indice = 1 ; indice <= numar_noduri ; indice++)
{ cantitate[lant[indice] + 1]++; }
for (int indice = 2 ; indice <= lant[0] + 1 ; indice++)
{ cantitate[indice] += cantitate[indice - 1]; }
for (int indice = 1 ; indice <= numar_noduri ; indice++)
{ invers[pozitie[indice] += cantitate[lant[indice]]] = indice; }
for (int indice = 1 ; indice <= lant[0] ; indice++)
{ adaos[indice + 1] = Build(1 , cantitate[indice] , cantitate[indice + 1] , adaos[indice]); }
while (numar_operatii--)
{
int8_t tip;
cin >> tip;
if (tip == '0')
{
int nod;
cin >> nod;
Update(1 , 1 , cantitate[lant[nod] + 1] - cantitate[lant[nod]] , pozitie[nod] , adaos[lant[nod]]);
}
else
{
int nod_1 , nod_2;
cin >> nod_1 >> nod_2;
int raspuns = 0;
while (lant[nod_1] != lant[nod_2]) {
if (adancime[reprezentant[lant[nod_1]]] > adancime[reprezentant[lant[nod_2]]])
{
raspuns = max(raspuns , Query(1 , cantitate[lant[nod_1]] , cantitate[lant[nod_1] + 1] , pozitie[nod_1] , pozitie[reprezentant[lant[nod_1]]] , adaos[lant[nod_1]]));
nod_1 = nod_sursa[reprezentant[lant[nod_1]]];
}
else
{
raspuns = max(raspuns , Query(1 , cantitate[lant[nod_2]] , cantitate[lant[nod_2] + 1] , pozitie[nod_2] , pozitie[reprezentant[lant[nod_2]]] , adaos[lant[nod_2]]));
nod_2 = nod_sursa[reprezentant[lant[nod_2]]];
}
}
raspuns = max(raspuns , Query(1 , cantitate[lant[nod_1]] , cantitate[lant[nod_1] + 1] , min(pozitie[nod_1] , pozitie[nod_2]) , max(pozitie[nod_1] , pozitie[nod_2]) , adaos[lant[nod_1]]));
cout << raspuns << '\n';
}
}
cout.close(); cin.close();
return 0;
}