#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int NMAX = 100000;
vector <int> T[NMAX + 5];
int lvl[NMAX + 5], tata[NMAX + 5], path_end[NMAX + 5], ord;//path_end[i] = nivelul la care se termina poteca i
int v[NMAX + 5], n;
vector <vector <int> > paths_list;
vector <int> emptyv;
int noduri[NMAX + 5], path[NMAX + 5], nr_paths;
void dfsHPD(int u){
int v, i, nod = -1;
for(i = 0; i < T[u].size(); i ++){
v = T[u][i];
if(!lvl[v] && v != 1){
lvl[v] = lvl[u] + 1;
tata[v] = u;
dfsHPD(v);
noduri[u] += noduri[v];
if(nod == -1 || noduri[v] > noduri[nod])
nod = v;
}
}
noduri[u] ++;
if(noduri[u] > 1){
path[u] = path[nod];
paths_list[path[nod]].push_back(u);
for(i = 0; i < T[u].size(); i ++){
v = T[u][i];
if(v != tata[u] && v != nod)
path_end[path[v]] = lvl[v];
}
}
else{
path[u] = ++ nr_paths;
paths_list.push_back(emptyv);
paths_list[nr_paths].push_back(u);
}
}
//AINT
int aint[4 * NMAX + 5], all_paths[NMAX + 5];
void build(int nod, int st, int dr){
if(st == dr)
aint[nod] = v[all_paths[st]];
else
{
int med = (st + dr) / 2;
build(nod<<1, st, med);
build((nod << 1)^1, med + 1, dr);
aint[nod] = max(aint[nod<<1], aint[(nod<<1)^1]);
}
}
void update(int nod, int st, int dr, int poz){
if(st == dr)
aint[nod] = v[all_paths[poz]];
else{
int med = (st + dr) / 2;
if(poz <= med)
update(nod<<1, st, med, poz);
else
update((nod<<1)^1, med + 1, dr, poz);
aint[nod] = max(aint[nod<<1], aint[(nod<<1)^1]);
}
}
int qa, qb, sol;
void queryaint(int nod, int st, int dr){
if(qa <= st && dr <= qb)
sol = max(sol, aint[nod]);
else{
int med = (st + dr) / 2;
if(qa <= med)
queryaint(nod << 1, st, med);
if(qb > med)
queryaint((nod<<1)^1, med + 1, dr);
}
}
int paths_starts[NMAX + 5], pos[NMAX + 5];//pos[i]-pozitia nodului i in all_paths; all_paths reprezinta reuniunea tuturor lanturilor
int solve(int x, int y){
sol = 0;
while(path[x] != path[y]){
if(path_end[path[x]] >= path_end[path[y]]){
qa = paths_starts[path[x]];
qb = pos[x];
queryaint(1, 1, n);
x = tata[all_paths[paths_starts[path[x]]]];
}
else{
qa = paths_starts[path[y]];
qb = pos[y];
queryaint(1, 1, n);
y = tata[all_paths[paths_starts[path[y]]]];
}
}
if(lvl[x] > lvl[y])
swap(x, y);
qa = pos[x];
qb = pos[y];
queryaint(1, 1, n);
return sol;
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int m, i, j, x, y, q;
scanf("%d%d", &n, &m);
for(i = 1; i <= n; i ++)
scanf("%d", &v[i]);
for(i = 1; i < n; i ++){
scanf("%d%d", &x, &y);
T[x].push_back(y);
T[y].push_back(x);
}
paths_list.push_back(emptyv);
dfsHPD(1);
int k = 0;
for(i = 1; i <= nr_paths; i ++){
paths_starts[i] = k + 1;
for(j = paths_list[i].size() - 1 ; j >= 0 ; j --){
all_paths[++ k] = paths_list[i][j];
pos[paths_list[i][j]] = k;
}
}
build(1, 1, n);
for(i = 1 ; i <= m ; i ++){
scanf("%d%d%d", &q, &x, &y);
if(q == 0){
v[x] = y;
update(1, 1, n, pos[x]);
}
else
printf("%d\n", solve(x, y));
}
return 0;
}