#include <bits/stdc++.h>
#define dimn 100001
#define dimm 100001
const int global_root = 1;
std::ifstream f("heavypath.in");
std::ofstream g("heavypath.out");
//vai de capul meu ce sunt cu declararile astea si ce am ajuns sa fac cu viata mea
int N, Q;
int parent[dimn];
int v[dimn], nivel[dimn];
int nc, nchain[dimn], gr[dimn];
int ord[dimn]; //ord[i] - pozitia elementului i in lant
std::list <int> adj[dimn];
std::vector <int> chain[dimn], tree[dimn];
void dfs(int start = global_root, int level = 1) {
nivel[start] = level;
bool leaf = true;
int nod = 0;
gr[start] = 1;
for(auto vec:adj[start])
if(!nivel[vec]) {
dfs(vec, level+1);
parent[vec] = start;
leaf = false;
if(gr[vec] > gr[nod]) nod = vec;
gr[start] += gr[vec];
}
if(leaf) nchain[start] = ++nc;
else nchain[start] = nchain[nod];
chain[nchain[start]].push_back(start);
}
void init(int ord, int left, int right, int nod=1) {
if(left == right) {
tree[ord][nod] = v[chain[ord][left]];
return;
} int mij = (left+right)/2;
init(ord, left, mij, 2*nod);
init(ord, mij+1, right, 2*nod+1);
tree[ord][nod] = std::max(tree[ord][2*nod], tree[ord][2*nod+1]);
}
void arbore() {
for (int i=1, j; i<=nc; i++) {
std::reverse(chain[i].begin(), chain[i].end());
for (j=0; j<chain[i].size(); j++)
ord[chain[i][j]] = j;
tree[i].resize(4*chain[i].size()+5);
init(i, 0, chain[i].size()-1);
}
}
void update(int ntree, int pos, int left, int right, int nod=1) {
if(left==right) {
tree[ntree][nod] = v[chain[ntree][left]];
return;
} int mij = (left+right)/2;
if(pos<=mij) update(ntree, pos, left, mij, 2*nod);
else update(ntree, pos, mij+1, right, 2*nod+1);
tree[ntree][nod] = std::max(tree[ntree][2*nod], tree[ntree][2*nod+1]);
}
int max_interval(int ntree, int s, int d, int left, int right, int nod=1) {
if(s<=left && right<=d) return tree[ntree][nod];
int mij = (left+right)/2;
int max = -2e9;
if(s<=mij) max = max_interval(ntree, s, d, left, mij, 2*nod);
if(mij<d) max = std::max(max, max_interval(ntree, s, d, mij+1, right, 2*nod+1));
return max;
}
int query(int y, int x) {
int res = INT_MIN;
int a, b;
while(nchain[x] != nchain[y]) {
if(nivel[chain[nchain[x]][0]] < nivel[chain[nchain[y]][0]])
std::swap(x, y);
a = 0; b = ord[x];
res = std::max(res, max_interval(nchain[x], a, b, 0, chain[nchain[x]].size()-1));
x = parent[chain[nchain[x]][0]];
}
return std::max(res, max_interval(nchain[x], std::min(ord[x], ord[y]), std::max(ord[x], ord[y]), 0, chain[nchain[x]].size()-1));
}
void citire() {
f >> N >> Q;
for (int i=0; i<N; i++)
f >> v[i+1], parent[i+1] = i+1;
for (int i=0, y, x; i<N-1; i++) {
f >> y >> x;
adj[y].push_back(x);
adj[x].push_back(y);
}
}
void rezolvare() {
dfs();
arbore();
for (int i=0, t, y, x; i<Q; i++) {
f >> t >> y >> x;
if(t) g << query(y, x) << "\n";
else {
v[y] = x;
update(nchain[y], ord[y], 0, chain[nchain[y]].size()-1);
}
}
}
int main()
{
citire();
rezolvare();
return 0;
}