#include <fstream>
#include <vector>
using namespace std;
ifstream cin ("heavypath.in");
ofstream cout ("heavypath.out");
class AINT {
private:
AINT *urmatorul[2] = { };
int lungime = 0 , maxim = 0;
void insert (const int stanga , const int dreapta , const int pozitie , const int valoare)
{
if (stanga == dreapta)
{ maxim = valoare; return; }
const int mijloc = (stanga + dreapta) >> 1;
if (pozitie <= mijloc)
{
if (urmatorul[0] == NULL)
{ urmatorul[0] = new AINT; }
urmatorul[0] -> insert(stanga , mijloc , pozitie , valoare);
maxim = max(maxim , urmatorul[0] -> maxim);
return;
}
if (urmatorul[1] == NULL)
{ urmatorul[1] = new AINT; }
urmatorul[1] -> insert(mijloc + 1 , dreapta , pozitie , valoare);
maxim = max(maxim , urmatorul[1] -> maxim);
}
int query (const int stanga , const int dreapta , const int stanga_interval , const int dreapta_interval)
{
if (stanga_interval <= stanga && dreapta <= dreapta_interval)
{ return maxim; }
const int mijloc = (stanga + dreapta) >> 1;
if (dreapta_interval <= mijloc) { return (urmatorul[0] == NULL ? 0 : urmatorul[0] -> query(stanga , mijloc , stanga_interval , dreapta_interval)); }
if (stanga_interval > mijloc) { return (urmatorul[1] == NULL ? 0 : urmatorul[1] -> query(mijloc + 1 , dreapta , stanga_interval , dreapta_interval)); }
return max((urmatorul[0] == NULL ? 0 : urmatorul[0] -> query(stanga , mijloc , stanga_interval , dreapta_interval)) , (urmatorul[1] == NULL ? 0 : urmatorul[1] -> query(mijloc + 1 , dreapta , stanga_interval , dreapta_interval)));
}
public:
void push_back (const int valoare) { (*this).insert(1 , 100000 , ++lungime , valoare); }
void update (const int pozitie , const int valoare) { (*this).insert(1 , 100000 , pozitie , valoare); }
int query (const int stanga , const int dreapta) { return (*this).query(1 , 100000 , stanga , dreapta); }
int size () { return lungime; }
void Parcurgere (const int stanga , const int dreapta)
{
if (stanga == dreapta)
{ cout << maxim << ' '; }
const int mijloc = (stanga + dreapta) >> 1;
if (urmatorul[0]) { urmatorul[0] -> Parcurgere(stanga , mijloc); }
if (urmatorul[1]) { urmatorul[1] -> Parcurgere(mijloc + 1 , dreapta); }
}
} *candidati[100001];
vector <int> adiacenta[100001];
int valoare[100001] , lant[100001] , pozitie_lant[100001] , urmatorul[100001] , adancime[100001];
void Descompunere (const int nod_actual , const int nod_sursa)
{
adancime[nod_actual] = adancime[nod_sursa] + 1;
if (adiacenta[nod_actual].size() == 1 && nod_sursa)
{
lant[nod_actual] = ++lant[0];
candidati[lant[nod_actual]] = new AINT;
candidati[lant[nod_actual]] -> push_back(valoare[nod_actual]);
urmatorul[lant[nod_actual]] = nod_sursa;
pozitie_lant[nod_actual] = 1;
return;
}
int legat = 0;
for (auto nod_vecin : adiacenta[nod_actual]) {
if (nod_vecin != nod_sursa)
{
Descompunere(nod_vecin , nod_actual);
if (candidati[lant[nod_vecin]] -> size() > candidati[lant[legat]] -> size())
{ legat = nod_vecin; }
}
}
lant[nod_actual] = lant[legat];
candidati[lant[legat]] -> push_back(valoare[nod_actual]);
pozitie_lant[nod_actual] = candidati[lant[legat]] -> size();
urmatorul[lant[nod_actual]] = nod_sursa;
}
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]); }
Descompunere(1 , 0);
while (numar_operatii--)
{
uint16_t tip;
cin >> tip;
switch (tip)
{
case 0: { int nod , valoare; cin >> nod >> valoare; candidati[lant[nod]] -> update(pozitie_lant[nod] , valoare); }
break;
case 1:
{
int nod_1 , nod_2;
cin >> nod_1 >> nod_2;
int maxim = 0;
while (true)
{
if (lant[nod_1] == lant[nod_2]) {
maxim = max(maxim , candidati[lant[nod_1]] -> query(min(pozitie_lant[nod_1] , pozitie_lant[nod_2]) , max(pozitie_lant[nod_1] , pozitie_lant[nod_2])));
break;
}
if (adancime[urmatorul[lant[nod_1]]] > adancime[urmatorul[lant[nod_2]]])
{
maxim = max(maxim , candidati[lant[nod_1]] -> query(pozitie_lant[nod_1] , candidati[lant[nod_1]] -> size()));
nod_1 = urmatorul[lant[nod_1]];
continue;
}
maxim = max(maxim , candidati[lant[nod_2]] -> query(pozitie_lant[nod_2] , candidati[lant[nod_2]] -> size()));
nod_2 = urmatorul[lant[nod_2]];
}
cout << maxim << '\n';
}
break;
}
}
cout.close(); cin.close();
return 0;
}