#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
const int nmax = 100005;
int n, m, value[nmax], nivel[nmax], cnt[nmax], nrLanturi = 1, nNod[nmax], whatLant[nmax], whatPos[nmax], parent[nmax];
vector <int> G[nmax], lant[nmax], aint[nmax];
void dfs(int nod, int tata){
int maxim = 0, nodMaxim = -1;
cnt[nod] = 1;
for (auto it : G[nod]){
if (it == tata){
continue;
}
parent[it] = nod;
nivel[it] = nivel[nod] + 1;
dfs(it, nod);
if (cnt[it] > maxim){
maxim = cnt[it];
nodMaxim = it;
}
cnt[nod] += cnt[it];
}
nNod[nod] = nodMaxim ;
}
void dfs2(int nod, int tata){
lant[whatLant[nod]].push_back(nod);
whatPos[nod] = lant[whatLant[nod]].size() - 1;
if (nNod[nod] != -1){
whatLant[nNod[nod]] = whatLant[nod];
dfs2(nNod[nod], nod);
for (auto it : G[nod]){
if (it == tata || it == nNod[nod]){
continue;
}
dfs2(it, nod);
}
}
}
void Build(int l, int nod, int st, int dr){
if (st == dr){
aint[l][nod] = value[lant[l][st]];
return;
}
int mid = (st + dr) / 2;
Build(l, nod * 2, st, mid);
Build(l, nod * 2 + 1, mid + 1, dr);
aint[l][nod] = max(aint[l][nod * 2], aint[l][nod * 2 + 1]);
}
void Update(int l, int nod, int st, int dr, int pos){
if (st == dr){
aint[l][nod] = value[lant[l][st]];
return;
}
int mid = (st + dr) / 2;
if (pos <= mid){
Update(l, nod * 2, st, mid, pos);
}
else{
Update(l, nod * 2 + 1, mid + 1, dr, pos);
}
aint[l][nod] = max(aint[l][nod * 2], aint[l][nod * 2 + 1]);
}
int Query(int l, int nod, int st, int dr, int x, int y){
if (st > y || dr < x){
return 0;
}
if (st >= x && dr <= y){
return aint[l][nod];
}
int mid = (st + dr) / 2;
return max(Query(l, nod * 2, st, mid, x, y), Query(l, nod * 2 + 1, mid + 1, dr, x, y));
}
int Query2(int x, int y){
int ans = max(value[x], value[y]);
while (x != y){
if (whatLant[x] == whatLant[y]){
if (nivel[x] > nivel[y]){
ans = max(ans, Query(whatLant[x], 1, 0, lant[whatLant[x]].size() - 1, whatPos[y], whatPos[x]));
}
else{
ans = max(ans, Query(whatLant[x], 1, 0, lant[whatLant[x]].size() - 1, whatPos[x], whatPos[y]));
}
x = y;
}
else{
int firstX = lant[whatLant[x]][0], firstY = lant[whatLant[y]][0];
if (nivel[firstX] > nivel[firstY]){
ans = max(ans, Query(whatLant[x], 1, 0, lant[whatLant[x]].size() - 1, 0, whatPos[x]));
x = parent[firstX];
}
else{
ans = max(ans, Query(whatLant[y], 1, 0, lant[whatLant[y]].size() - 1, 0, whatPos[y]));
y = parent[firstY];
}
}
}
return ans;
}
int main(){
fin >> n >> m;
for (int i = 1; i <= n; ++i){
fin >> value[i];
whatLant[i] = i;
}
for (int i = 1; i < n; ++i){
int x, y;
fin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1, 0);
dfs2(1, 0);
vector <int> viz(n + 3);
for (int i = 1; i <= n; ++i){
int l = whatLant[i];
if (viz[l] == 0){
viz[l] = 1;
aint[l].resize(3 * lant[l].size() + 67);
Build(l, 1, 0, lant[l].size() - 1);
}
}
while (m--){
int p, x, y;
fin >> p >> x >> y;
if (p == 0){
int l = whatLant[x];
int pos = whatPos[x];
value[x] = y;
Update(l, 1, 0, lant[l].size() - 1, pos);
}
else{
fout << Query2(y, x) << "\n";
}
}
fin.close();
fout.close();
return 0;
}