#include <bits/stdc++.h>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
vector <int> G[100005];
int v[100005];
int nrf[100005];
int t[100005];
int depth[100005];
int pathid[100005];
vector <int> paths[100005];
vector <int> AINT[100005];
int nrpath;
void dfs(int nod, int p){
int best = 0;
t[nod] = p;
nrf[nod] = 1;
depth[nod] = depth[t[nod]] + 1;
vector <int> :: iterator it;
for(it = G[nod].begin(); it != G[nod].end(); it++){
int x = *it;
if(!depth[x]){
dfs(x,nod);
nrf[nod] += nrf[x];
if(nrf[x] > nrf[best]) best = x;
}
}
if(!best){
pathid[nod] = ++nrpath;
paths[pathid[nod]].push_back(nod);
}
else{
pathid[nod] = pathid[best];
paths[pathid[best]].push_back(nod);
}
}
inline int position(int nod){
return depth[nod] - depth[paths[pathid[nod]][0]] + 1;
}
inline int path_depth(int nod){
return depth[paths[pathid[nod]][0]];
}
void update_aint(vector <int> &aint, int nod, int st, int dr, int poz, int val){
if(st == dr){
aint[nod] = val;
return;
}
int med = (st + dr) >> 1;
if(poz <= med) update_aint(aint,2 * nod, st, med, poz, val);
else update_aint(aint,2 * nod + 1, med + 1, dr, poz, val);
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
int query_aint(vector <int> &aint, int nod, int st, int dr, int l, int r){
if(l <= st && dr <= r) return aint[nod];
int med = (st + dr) >> 1,a1 = 0,a2 = 0;
if(l <= med) a1 = query_aint(aint, 2 * nod, st, med, l,r);
if(r > med) a2 = query_aint(aint, 2 * nod + 1, med + 1, dr, l,r);
return max(a1,a2);
}
void update_path(int nod, int val){
v[nod] = val;
update_aint(AINT[pathid[nod]], 1, 1, paths[pathid[nod]].size(), position(nod), v[nod]);
}
int first_on_path(int nod){
return paths[pathid[nod]][0];
}
int path_max(int nod1, int nod2){
int id = pathid[nod1];
int x = position(nod1);
int y = position(nod2);
if(x > y) swap(x,y);
return query_aint(AINT[id], 1, 1, paths[id].size(), x, y);
}
int query(int x, int y){
int rez = 0;
while(pathid[x] != pathid[y]){
if(path_depth(x) < path_depth(y)) swap(x,y);
rez = max(rez, path_max(first_on_path(x),x));
x = t[first_on_path(x)];
}
rez = max(rez, path_max(x,y));
return rez;
}
int main()
{
int n,i,j,m,u,w;
fin >> n >> m;
for(i = 1; i <= n; i++) fin >> v[i];
for(i = 1; i < n; i++){
fin >> u >> w;
G[u].push_back(w);
G[w].push_back(u);
}
dfs(1,0);
for(i = 1; i <= nrpath; i++){
reverse(paths[i].begin(), paths[i].end());
AINT[i] = vector<int>(4 * (int)paths[i].size() + 1, 0);
vector <int> :: iterator it;
for(it = paths[i].begin(); it != paths[i].end(); it++) update_path(*it, v[*it]);
}
while(m--){
int c,x,y;
fin >> c >> x >> y;
if(!c) update_path(x,y);
else fout << query(x,y) << "\n";
}
return 0;
}