#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
const int NMAX = 100002;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
struct noduri {
int val; ///val cur
int tata, depth;
int lant; ///actual lantul
int weight = 0; ///cate schimburi maxim de lanturi
int id; ///locul din topo
}v[NMAX];
vector <vector <int>> adj;
vector <int> l; ///cel mai de sus nr dintr-un lant
void dfs(int start) {
bool ok = 0;
for(auto nod : adj[start]) {
if(v[start].tata == nod)
continue;
ok = 1;
v[nod].tata = start;
v[nod].depth = v[start].depth + 1;
dfs(nod);
}
if(!ok) { ///frunza
v[start].lant = l.size();
l.push_back(start);
v[start].weight = 1;
return;
}
int maxx = 0, cnt = 0, nou;
for(auto nod : adj[start]) {
if(v[start].tata == nod)
continue;
if(v[nod].weight > maxx) {
maxx = v[nod].weight;
nou = v[nod].lant;
cnt++;
}
else if(v[nod].weight == maxx)
cnt++;
}
v[start].lant = nou;
v[start].weight = maxx;
if(cnt > 1)
v[start].weight++;
l[nou] = start;
}
bool cmp(int a, int b) {
if(v[a].lant != v[b].lant)
return v[a].lant < v[b].lant;
return v[a].depth > v[b].depth; ///ULTIMUL din lant e cel de CEL mai sus
}
int topo[NMAX];
void reorder(int n) {
for(int i = 1; i <= n; i++)
topo[i] = i;
sort(topo + 1, topo + n + 1, cmp);
for(int i = 1; i <= n; i++) { ///reordonam
v[topo[i]].id = i;
}
}
int aint[4 * NMAX];
void build(int nod, int st, int dr) {
if(st == dr) {
aint[nod] = v[topo[st]].val;
return;
}
int mid = (st + dr) / 2;
build(2 * nod, st, mid);
build(2 * nod + 1, mid + 1, dr);
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
void update(int nod, int st, int dr, int pos, int val) {
if(pos < st || dr < pos)
return;
if(st == dr) {
aint[nod] = val;
return;
}
int mid = (st + dr) / 2;
update(2 * nod, st, mid, pos, val);
update(2 * nod + 1, mid + 1, dr, pos, val);
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
int query(int nod, int st, int dr, int pos1, int pos2) {
if(pos2 < st || dr < pos1)
return -1;
if(pos1 <= st && dr <= pos2)
return aint[nod];
int mid = (st + dr) / 2;
return max(query(2 * nod, st, mid, pos1, pos2),
query(2 * nod + 1, mid + 1, dr, pos1, pos2));
}
int n;
int findmax(int a, int b) {
int ans = -1;
//cout << "Ah shit here we go again\n";
while(v[a].lant != v[b].lant) {
int nr1 = l[v[a].lant], nr2 = l[v[b].lant];
//cout << a << " " << nr1 << " " << b << " " << nr2 << '\n';
if(v[nr1].depth < v[nr2].depth) { ///il vrem pe a mai jos
swap(a, b);
swap(nr1, nr2);
}
ans = max(ans, query(1, 1, n, v[a].id, v[nr1].id));
a = v[nr1].tata;
}
if(v[a].depth < v[b].depth)
swap(a, b);
ans = max(ans, query(1, 1, n, v[a].id, v[b].id));
return ans;
}
int main() {
int m;
cin >> n >> m;
adj.resize(n + 1);
for(int i = 1; i <= n; i++)
cin >> v[i].val;
for(int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
adj[a].push_back(b);
adj[b].push_back(a);
}
dfs(1); ///imparti pe lanturi
/*for(int i = 1; i <= n; i++)
cout << v[i].lant << " " << v[i].depth << '\n';*/
reorder(n);
/*for(int i = 1; i <= n; i++)
cout << topo[i] << " ";*/
build(1, 1, n);
/*for(int i = 1; i <= n; i++)
cout << query(1, 1, n, v[i].id, v[i].id) << " ";*/
while(m--) {
int tip, a, b;
cin >> tip >> a >> b;
if(tip == 0) ///update, v[a] = b
update(1, 1, n, v[a].id, b);
else ///query de dist (a, b)
cout << findmax(a, b) << '\n';
}
return 0;
}