#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int LOGN = 16;
const int NMAX = 100000;
class aint {
private:
vector<int> maxim;
void upd(int nod, int nst, int ndr, int upoz, int val) {
if(nst == ndr)
maxim[nod] = val;
else {
int mij = (nst + ndr) / 2;
if(upoz <= mij)
upd(2 * nod, nst, mij, upoz, val);
else
upd(2 * nod + 1, mij + 1, ndr, upoz, val);
maxim[nod] = max(maxim[2 * nod], maxim[2 * nod + 1]);
}
}
int qry(int nod, int nst, int ndr, int qst, int qdr) {
if(qst > ndr || qdr < nst) return 0;
if(nst >= qst && ndr <= qdr) return maxim[nod];
int mij = (nst + ndr) / 2;
return max(qry(2 * nod, nst, mij, qst, qdr), qry(2 * nod + 1, mij + 1, ndr, qst, qdr));
}
public:
int sz;
void init(vector<int> &v, int nod, int nst, int ndr) {
if(nst == ndr)
maxim[nod] = v[nst];
else {
int mij = (nst + ndr) / 2;
init(v, 2 * nod, nst, mij);
init(v, 2 * nod + 1, mij + 1, ndr);
maxim[nod] = max(maxim[2 * nod], maxim[2 * nod + 1]);
}
}
aint() {
sz = 0;
}
aint(vector<int> &v) {
sz = v.size();
maxim.resize(4 * v.size());
init(v, 1, 0, v.size() - 1);
}
void update(int poz, int val) {
upd(1, 0, sz - 1, poz, val);
}
int query(int qst) {
return qry(1, 0, sz - 1, qst, sz - 1);
}
int query(int qst, int qdr) {
return qry(1, 0, sz - 1, qst, qdr);
}
};
int n, m;
int val[NMAX + 5], path[NMAX + 5], path_poz[NMAX + 5], h[NMAX + 5];
vector<int> arb[NMAX + 5], path_dad;
vector<aint> aints;
vector<vector<int>> paths;
int path_decomposition(int nod, int dad) {
bool frunza = true;
int fii = 1, max_fii = 0, heaviest = -1;
h[nod] = h[dad] + 1;
for(int vec: arb[nod])
if(vec != dad) {
frunza = false;
int fii_vec = path_decomposition(vec, nod);
fii += fii_vec;
if(fii_vec > max_fii) {
max_fii = fii_vec;
heaviest = path[vec];
}
}
if(!frunza) {
paths[heaviest].push_back(nod);
path[nod] = heaviest;
path_poz[nod] = paths[heaviest].size() - 1;
path_dad[heaviest] = dad;
}
else {
vector<int> new_path;
paths.push_back(new_path);
paths.back().push_back(nod);
path_dad.push_back(dad);
path[nod] = paths.size() - 1;
path_poz[nod] = 0;
}
return fii;
}
int query(int nod1, int nod2) {
int ans = 0;
while(path[nod1] != path[nod2])
if(h[path_dad[path[nod1]]] >= h[path_dad[path[nod2]]]) {
ans = max(ans, aints[path[nod1]].query(path_poz[nod1]));
nod1 = path_dad[path[nod1]];
}
else {
ans = max(ans, aints[path[nod2]].query(path_poz[nod2]));
nod2 = path_dad[path[nod2]];
}
if(path_poz[nod1] > path_poz[nod2]) swap(nod1, nod2);
ans = max(ans, aints[path[nod1]].query(path_poz[nod1], path_poz[nod2]));
return ans;
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &val[i]);
for(int i = 1; i < n; i++) {
int x, y;
scanf("%d %d", &x, &y);
arb[x].push_back(y);
arb[y].push_back(x);
}
path_decomposition(1, 0);
for(int i = 0; i < paths.size(); i++) {
vector<int> vpath;
for(int crt: paths[i])
vpath.push_back(val[crt]);
aint new_aint = aint(vpath);
aints.push_back(new_aint);
}
for(int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d %d %d", &t, &x, &y);
if(t == 0)
aints[path[x]].update(path_poz[x], y);
else
printf("%d\n", query(x, y));
}
return 0;
}