#include <bits/stdc++.h>
using namespace std;
#define pb push_back
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int N = 1e5+2;
int n, m, nrp, p = 1;
int v[N], pos[N], t[N], sz[N], ord[N], a[4*N], niv[N];
vector<int> e[N];
vector<vector<int>> path;
void read(), upd(int,int), dfs(int), hld(), updAint(int,int);
int query(int, int), queryAint(int,int,int,int,int);
int main(){
read();
hld();
while (m--){
int tip, x, y; fin >> tip >> x >> y;
if (tip) fout << query(x, y) << '\n';
else {
upd(x,y);
}
}
return 0;
}
void read() {
fin >> n >> m;
while (p < n) p *= 2; p--;
for (int i = 1; i <= n; i++) fin >> v[i];
for (int i = 1; i < n; i++) {
int x, y; fin >> x >> y;
e[x].pb(y); e[y].pb(x);
}
}
void hld() {
path.pb({});
dfs(1); int k = 1;
for (int i = 1; i <= nrp; i++) {
reverse(path[i].begin(), path[i].end());
for (auto it: path[i]){
pos[it] = k + p;
a[k + p] = v[it];
k++;
}
}
for (int i = p; i; i--) a[i] = max(a[2*i], a[2*i+1]);
}
void dfs(int nod) {
int hvy = 0;
sz[nod] = 1;
niv[nod] = niv[t[nod]] + 1;
for (auto it: e[nod]){
if (it == t[nod]) continue;
t[it] = nod; dfs(it);
if (sz[it] > sz[hvy]) {hvy = it; ord[nod] = ord[it];}
sz[nod] += sz[it];
}
if (!hvy){
nrp++; path.pb({});
ord[nod] = nrp;
}
path[ord[nod]].pb(nod);
}
void upd(int x, int y){
updAint(pos[x], y);
}
int query(int x, int y){
int ret = 0;
while (ord[x] != ord[y]){ //nu sunt pe acelasi lant
if (niv[x] < niv[y]) swap(x, y);
ret = max(ret, queryAint(1, 1, p + 1, pos[path[ord[x]][0]] - p, pos[x] - p));
x = t[path[ord[x]][0]];
}
if (niv[x] > niv[y]) swap(x, y);
ret = max(ret, queryAint(1, 1, p+1, pos[x] - p, pos[y] - p));
return ret;
}
int queryAint(int nod, int l, int r, int ql, int qr){
if (r < ql || qr < l) return 0;
if (ql <= l && r <= qr) return a[nod];
int mi = (l + r) / 2;
return max(queryAint(2*nod, l, mi, ql, qr), queryAint(2*nod+1, mi+1, r, ql, qr));
}
void updAint(int pos, int val){
v[pos - p] = val;
a[pos] = val; pos /= 2;
while (pos){
a[pos] = max(a[2*pos], a[2*pos+1]);
pos /= 2;
}
}