#include <bits/stdc++.h>
using namespace std;
#define pb push_back
using ll = long long;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int N = 1e5+3;
int n, m, nrp, p = 1, v[N], wp[N], sz[N], niv[N], t[N], a[4*N], pos[N];
vector<int> e[N];
vector<vector<int>> path;
void read(), hpd(), dfs(int), updAint(int,int);
int query(int,int), queryAint(int,int,int,int,int);
int main()
{
read();
hpd();
while (m--) {
int tip, x, y; fin >> tip >> x >> y;
if (tip) fout << query(x, y) << '\n';
else updAint(pos[x], y);
}
}
void read() {
fin >> n >> m;
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 hpd() {
dfs(1);
int k = 1;
while (p < n) p *= 2; p--;
for (auto &pth: path){
reverse(pth.begin(), pth.end());
for (auto el: pth) {
a[k + p] = v[el];
pos[el] = k++;
}
}
for (int i = p; i; i--)
a[i] = max(a[2*i], a[2*i+1]);
}
void dfs(int nod) {
niv[nod] = niv[t[nod]] + 1;
sz[nod] = 1;
int mx = 0;
for (auto it: e[nod]) {
if (it == t[nod]) continue;
t[it] = nod; dfs(it);
if (sz[it] > sz[mx]){
mx = it;
wp[nod] = wp[it];
}
sz[nod] += sz[it];
}
if (!mx){
path.pb({});
wp[nod] = nrp; nrp++;
}
path[wp[nod]].pb(nod);
}
void updAint(int k, int val){
k += p; a[k] = val; k /= 2;
while (k) { a[k] = max(a[2 * k], a[2 * k + 1]); k /= 2; }
}
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));
}
int query(int x, int y) {
int ret = 0;
while (wp[x] != wp[y]){
if (niv[path[wp[x]][0]] < niv[path[wp[y]][0]])
swap(x, y);
ret = max(ret, queryAint(1, 1, p+1, pos[path[wp[x]][0]], pos[x]));
x = t[path[wp[x]][0]];
}
if (niv[x] > niv[y]) swap(x, y);
ret = max(ret, queryAint(1, 1, p + 1, pos[x], pos[y]));
return ret;
}