#include <fstream>
#include <vector>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int Nmax = 100005;
struct nod{
int val;
int adancime;
int marime_subarbore;
int parinte;
int capat_lant;
int fiu_heavy;
int timp_procesare;
vector<int> vecini;
};
int n, q, timp;
int ordine_liniarizare[Nmax];
nod arbore[Nmax];
int aint[4 * Nmax];
void aint_build(int nod, int st, int dr){
if(st == dr){
aint[nod] = arbore[ordine_liniarizare[st]].val;
return;
}
int mid = (st + dr) / 2;
aint_build(2 * nod, st, mid);
aint_build(2 * nod + 1, mid + 1, dr);
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
void aint_update(int nod, int st, int dr, int poz, int val){
if(st == poz && dr == poz){
aint[nod] = val;
return;
}
int mid = (st + dr) / 2;
if(poz <= mid){
aint_update(2 * nod, st, mid, poz, val);
}
else{
aint_update(2 * nod + 1, mid + 1, dr, poz, val);
}
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
int aint_query(int nod, int st, int dr, int poz_st, int poz_dr){
if(poz_st > poz_dr){
swap(poz_st, poz_dr);
}
if(st == poz_st && dr == poz_dr){
return aint[nod];
}
int mid = (st + dr) / 2;
if(poz_dr <= mid){
return aint_query(2 * nod, st, mid, poz_st, poz_dr);
}
else if(mid < poz_st){
return aint_query(2 * nod + 1, mid + 1, dr, poz_st, poz_dr);
}
else{
return max(aint_query(2 * nod, st, mid, poz_st, mid), aint_query(2 * nod + 1, mid + 1, dr, mid + 1, poz_dr));
}
}
void citire_arbore(){
int nod1, nod2;
fin >> n >> q;
for(int i = 1; i <= n; i++){
fin >> arbore[i].val;
}
for(int i = 1; i < n; i++){
fin >> nod1 >> nod2;
arbore[nod1].vecini.push_back(nod2);
arbore[nod2].vecini.push_back(nod1);
}
}
void dfs_adancimi(int nod, int parinte){
arbore[nod].parinte = parinte;
arbore[nod].fiu_heavy = 0;
arbore[nod].marime_subarbore = 1;
arbore[nod].adancime = arbore[parinte].adancime + 1;
for(int vecin : arbore[nod].vecini){
if(vecin != parinte){
dfs_adancimi(vecin, nod);
arbore[nod].marime_subarbore += arbore[vecin].marime_subarbore;
if(arbore[arbore[nod].fiu_heavy].marime_subarbore < arbore[vecin].marime_subarbore){
arbore[nod].fiu_heavy = vecin;
}
}
}
}
void dfs_liniarizare(int nod, int capat_lant){
arbore[nod].timp_procesare = ++timp;
arbore[nod].capat_lant = capat_lant;
ordine_liniarizare[timp] = nod;
if(arbore[nod].fiu_heavy){
dfs_liniarizare(arbore[nod].fiu_heavy, capat_lant);
}
for(int vecin : arbore[nod].vecini){
if(vecin != arbore[nod].parinte && vecin != arbore[nod].fiu_heavy){
dfs_liniarizare(vecin, vecin);
}
}
}
void initializare_hld(){
dfs_adancimi(1, 0);
timp = 0;
dfs_liniarizare(1, 1);
aint_build(1, 1, n);
}
void hld_update(int poz, int val){
arbore[poz].val = val;
aint_update(1, 1, n, arbore[poz].timp_procesare, val);
}
int hld_query(int st, int dr){
int capat_st, capat_dr;
capat_st = arbore[st].capat_lant;
capat_dr = arbore[dr].capat_lant;
if(capat_st == capat_dr){
return aint_query(1, 1, n, arbore[st].timp_procesare, arbore[dr].timp_procesare);
}
else if(arbore[capat_st].adancime > arbore[capat_dr].adancime){
return max(aint_query(1, 1, n, arbore[st].timp_procesare, arbore[capat_st].timp_procesare), hld_query(arbore[capat_st].parinte, dr));
}
else{
return max(aint_query(1, 1, n, arbore[dr].timp_procesare, arbore[capat_dr].timp_procesare), hld_query(st, arbore[capat_dr].parinte));
}
}
void citire_si_rezolvare_interogari(){
int tip, poz, val, capat_st, capat_dr;
for(int i = 1; i <= q; i++){
fin >> tip;
if(tip == 0){
fin >> poz >> val;
hld_update(poz, val);
}
else{
fin >> capat_st >> capat_dr;
fout << hld_query(capat_st, capat_dr) << '\n';
}
}
}
int main(){
citire_arbore();
initializare_hld();
citire_si_rezolvare_interogari();
return 0;
}