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