#include <cstdio>
#include <vector>
#include <bitset>
#include <algorithm>
using namespace std;
const int nmx = 100002; /// numar maxim de noduri
int n,m; /// numar de noduri, numar de operatii
bitset <nmx> viz; /// viz[i] = true - nodul fu vizitat <-> false - nu fu
vector <int> lant[nmx], g[nmx]; /// lanturile si graful
vector <int> aint[nmx]; /// arborele de intervale
int val[nmx]; /// val[i] = costul nodului i
int care_lant[nmx]; /// care_lant[i] = lantul in care se afla nodul i
int poz_lant[nmx]; /// poz_lant[i] = pozitia nodului i in lant
int tata_lant[nmx]; /// tata_lant[i] = tatal lantului i
int nr_lanturi; /// numarul total de lanturi
int greutate[nmx]; /// greutate[i] = greutatea nodului i
int adancime[nmx]; /// adancimea[i] = adancimea nodului i
void citire() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%d", &val[i]);
for(int i = 1; i < n; ++i) {
int nod1, nod2;
scanf("%d %d", &nod1, &nod2);
g[nod1].push_back(nod2);
g[nod2].push_back(nod1);
}
}
void parcurgere(int nod) {
viz[nod] = true; /// marchez nodul ca fiind vizitat
greutate[nod] = 1; /// setez greutatea subarborelui cu radacina nod cu 1
bool frunza = true; /// presupunem ca nodul este frunza
int nod_max = -1; /// variabila in care retinem fiul cel mai greu (grasut)
for(vector<int>::iterator it = g[nod].begin(); it != g[nod].end(); ++it) {
if(viz[*it] == true) /// verificam daca nodul este tatal
continue; /// caz afirmativ, sarim peste el
frunza = false; /// in acest caz nodul nu este frunza
adancime[*it] = adancime[nod] + 1; /// setam adancimea fiului
parcurgere(*it); /// continuam parcurgerea pe fiu
greutate[nod] += greutate[*it]; /// adaugam greutatea subarborelui cu radacina *it
if(nod_max == -1) /// initializam nodul cel mai greu cu primul
nod_max = *it;
else if(greutate[*it] > greutate[nod_max]) /// verificam daca nodul acesta este mai greu
nod_max = *it; /// actualizam cel mai greu nod din toti fii
}
if(frunza == true) { /// daca nod este frunza, adaugam un nou lant
++ nr_lanturi; /// incrementam numarul de lanturi
care_lant[nod] = nr_lanturi; /// memoram in ce lant se afla nodul
lant[nr_lanturi].push_back(nod); /// adaugam nodul in noul lant
return;
}
care_lant[nod] = care_lant[nod_max]; /// lantul in care se afla nodul este acelasi cu fiul cel mai greu
lant[care_lant[nod]].push_back(nod); /// adaugam nodul in lantul copilului cel mai gras
for(vector<int>::iterator it = g[nod].begin(); it != g[nod].end(); ++it) {
if(*it == nod_max || adancime[*it] < adancime[nod]) /// daca nodul este cel mai gras sau
continue; /// tatal, sarim peste
tata_lant[care_lant[*it]] = nod; /// actualizam tatal lanturilor care se termina in *it
}
}
void construieste(int nod, int stanga, int dreapta, int nr_lant) {
if(stanga == dreapta) {
aint[nr_lant][nod] = val[lant[nr_lant][stanga - 1]]; /// am gasit pozitia in arborele de intervale si actualizam
int aux = aint[nr_lant][nod];
return; /// ne intoarcem
}
int mij = (stanga + dreapta) / 2; /// setam pivotul
construieste(2 * nod, stanga, mij, nr_lant); /// construim in stanga
construieste(2 * nod + 1, mij + 1, dreapta, nr_lant); /// construim in dreapta
aint[nr_lant][nod] = max(aint[nr_lant][2*nod],aint[nr_lant][2*nod+1]); /// actualizam baa
}
void creaza_lanturi() { /// construieste arborele de intervale
adancime[1] = 1; /// setam adancimea radacinii
parcurgere(1); /// parcurgem in adancime arborele
for(int i = 1; i <= nr_lanturi; ++i) { /// iteram prin lanturile create
reverse(lant[i].begin(),lant[i].end()); /// inversam ordinea nodurilor din lant ca sa fie
/// de la frunza la radacina
/// afisare intermediara a lanturilor grasute
/**for(vector<int>::iterator it = lant[i].begin(); it != lant[i].end(); ++it)
printf("%d ", *it);
printf("\n");**/
int paux = 0;
for(vector<int>::iterator it = lant[i].begin(); it != lant[i].end(); ++it)
poz_lant[*it] = ++paux;
aint[i].resize(lant[i].size()*4 + 2); /// alocam spatiu necesar ptr arborele lantului i
construieste(1,1,lant[i].size(),i); /// construim arborele de intervale pentru lantul i
}
}
void update(int nod, int stanga, int dreapta, int nr_lant, int p_lant, int update_val) {
/// nr_lant = numarul lantului in care se afla nodul
/// p_lant = pozitia in lant a nodului
/// update_val = valoarea pe care o atribuim
if(stanga == dreapta) { /// am gasit pozitia de updatat
aint[nr_lant][nod] = update_val; /// actualizam
return;
}
int mij = (stanga + dreapta) / 2;
if(p_lant <= mij) /// vedem unde tre sa cautam pozitia
update(2 * nod, stanga, mij, nr_lant, p_lant, update_val);
else
update(2 * nod + 1, mij + 1, dreapta, nr_lant, p_lant, update_val);
aint[nr_lant][nod] = max(aint[nr_lant][2 * nod],aint[nr_lant][2 * nod + 1]);
}
int query(int nod, int stanga, int dreapta, int qstanga, int qdreapta, int nr_lant) {
if(qstanga <= stanga && qdreapta >= dreapta){
int aux = aint[nr_lant][nod];
return aint[nr_lant][nod];
}
int mij = (stanga + dreapta) / 2;
int rez = 0; /// variabila in care retinem valoarea maxima din query-urile ce urmeaza
if(qstanga <= mij)
rez = max(rez, query(2 * nod, stanga, mij, qstanga, qdreapta, nr_lant));
if(qdreapta > mij)
rez = max(rez, query(2 * nod + 1, mij + 1, dreapta, qstanga, qdreapta, nr_lant));
return rez;
}
void rezolva() {
int tip, x, y;
for(int i = 1; i <= m; ++i) { /// iteram operatiile
scanf("%d %d %d", &tip, &x, &y);
if(tip == 0){
val[x] = y;
update(1,1,lant[care_lant[x]].size(),care_lant[x],poz_lant[x],y);
}
else {
int sol = 0; /// memoram valoarea maxima cautata
while(true) {
if(care_lant[x] == care_lant[y]) {
if(adancime[x] - adancime[tata_lant[care_lant[x]]] < adancime[y] - adancime[tata_lant[care_lant[y]]])
sol = max(sol,query(1,1,lant[care_lant[x]].size(),adancime[x] - adancime[tata_lant[care_lant[x]]],
adancime[y] - adancime[tata_lant[care_lant[y]]], care_lant[x]));
else
sol = max(sol,query(1,1,lant[care_lant[x]].size(),adancime[y] - adancime[tata_lant[care_lant[y]]],
adancime[x] - adancime[tata_lant[care_lant[x]]], care_lant[x]));
break;
}
if(adancime[tata_lant[care_lant[x]]] < adancime[tata_lant[care_lant[y]]])
swap(x,y);
sol = max(sol,query(1,1,lant[care_lant[x]].size(), 1, adancime[x] - adancime[tata_lant[care_lant[x]]], care_lant[x]));
x = tata_lant[care_lant[x]];
}
printf("%d\n", sol);
}
}
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
citire();
creaza_lanturi();
rezolva();
return 0;
}