#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;
ifstream in ("heavypath.in");
ofstream out ("heavypath.out");
//variabile
const int dim = 100005;
int level[dim],hz[dim],lant[dim],nod_tata[dim],valoare[dim],poz[dim];
vector<int>v[dim],aint[dim],start[dim];
int l,n,q,a,b,t,x,y;
// functie pentru sortare
bool cmp (int a, int b) {
return level[a] < level[b];
}
// dfs
int dfs (int nod, int nivel) {
int noduri = 0, maxim = 0,alfa = 0,ok = 0;
hz[nod] = 1;
level[nod] = nivel;
for (int i = 0; i < v[nod].size(); i ++) {
int vec = v[nod][i];
if (hz[vec] == 1)
continue;
ok = 1;
int vn = dfs (vec,nivel+1);
noduri += vn;
if (maxim < vn) {
maxim = vn;
alfa = vec;
}
}
if (ok == 0) {
start[++l].push_back (nod);
lant[nod] = l;
return 1;
}
start[lant[alfa]].push_back (nod);
lant[nod] = lant[alfa];
for (int i = 0; i < v[nod].size(); i ++) {
if (level[v[nod][i]] < level[nod] || lant[v[nod][i]] == lant[nod])
continue;
nod_tata[lant[v[nod][i]]] = nod;
}
return noduri+1;
}
// operatii aint
void build (int nod,int st, int dr, int ind) {
if (st == dr) {
aint[ind][nod] = valoare[start[ind][st-1]];
return;
}
int mid = (st + dr) >> 1;
build (nod<<1,st,mid,ind);
build (nod<<1|1,mid+1,dr,ind);
aint[ind][nod] = max (aint[ind][nod<<1], aint[ind][nod<<1|1]);
return;
}
void update (int nod, int st, int dr, int ind, int poz, int val) {
if (st > poz || dr < poz) {
return;
}
if (st == dr) {
aint[ind][nod] = val;
return;
}
int mid = (st + dr) >> 1;
update (nod<<1,st,mid,ind,poz,val);
update (nod<<1|1,mid+1,dr,ind,poz,val);
aint[ind][nod] = max (aint[ind][nod<<1], aint[ind][nod<<1|1]);
return;
}
int query (int nod, int st, int dr,int ind, int x, int y) {
if (st > y || dr < x) {
return 0;
}
if (st >= x && dr <= y) {
return aint[ind][nod];
}
int mid = (st + dr) >> 1;
int stanga = query (nod<<1,st,mid,ind,x,y);
int dreapta = query (nod<<1|1,mid+1,dr,ind,x,y);
return max (stanga, dreapta);
}
// main
int main (void) {
in >> n >> q;
for (int i = 1; i <= n; i ++) {
in >> valoare[i];
}
for (int i = 1; i < n; i ++) {
in >> a >> b;
v[a].push_back (b);
v[b].push_back (a);
}
dfs (1,1);
// creeaza aint pentru fiecare lant
for (int i = 1; i <= l; i ++) {
sort (start[i].begin(), start[i].end(), cmp);
for (int j = 0; j < start[i].size(); j ++) {
poz[start[i][j]] = j + 1;
}
for (int j = 0; j <= start[i].size()*4; j++) {
aint[i].push_back (0);
}
build (1,1,start[i].size(),i);
}
//operatii
for (int i = 1; i <= q; i ++) {
in >> t;
if (t == 0) {
in >> x >> y;
update(1,1,start[lant[x]].size(),lant[x],poz[x],y);
}
if (t == 1) {
in >> x >> y;
int maxim = 0;
while (lant[x] != lant[y]) {
if (level[nod_tata[lant[x]]] > level[nod_tata[lant[y]]]) {
maxim = max (maxim, query (1,1,start[lant[x]].size(),lant[x],1,poz[x]) );
x = nod_tata[lant[x]];
}
else {
maxim = max (maxim, query (1,1,start[lant[y]].size(),lant[y],1,poz[y]) );
y = nod_tata[lant[y]];
}
}
maxim = max (maxim,query(1,1,start[lant[y]].size(),lant[x],min(poz[x],poz[y]),max(poz[x],poz[y])));
out << maxim <<"\n";
}
}
return 0;
}