#include <bits/stdc++.h>
using namespace std;
ifstream f ("heavypath.in");
ofstream g ("heavypath.out");
constexpr int NMAX = 1e5 + 5;
int N, M;
int val[NMAX];
vector <int> G[NMAX];
int Size[NMAX];
int Id[NMAX];
int Size_Id[NMAX];
int First[NMAX];
int Max_Son[NMAX];
int Dad[NMAX];
int Level[NMAX];
struct Aint
{
int *A;
Aint(int size) : A(new int[4 * size])
{
}
void Update_Tree (int nod, int a, int b, int poz, int val) {
if (a == b) {
A[nod] = val;
return;
}
int mij = (a + b) / 2;
if (poz <= mij) Update_Tree(2*nod, a, mij, poz, val);
if (mij < poz) Update_Tree(2*nod+1, mij+1, b, poz, val);
A[nod] = max(A[2*nod], A[2*nod+1]);
}
int Query (int nod, int a, int b, int qa, int qb) {
if (qa <= a && b <= qb) return A[nod];
int mij = (a + b) / 2;
int Rez_1 = 0, Rez_2 = 0;
if (qa <= mij) Rez_1 = Query(2*nod, a, mij, qa, qb);
if (mij < qb) Rez_2 = Query(2*nod+1, mij+1, b, qa, qb);
return max(Rez_1, Rez_2);
}
};
vector <Aint*> Arbore;
void Dfs (int Node, int dad = -1, int lvl = 0) {
Level[Node] = lvl;
Size[Node] = 1;
Dad[Node] = dad;
for (auto it : G[Node]) {
if (it == dad) continue;
Dfs(it, Node, lvl+1);
Size[Node] += Size[it];
if (Size[it] > Size[Max_Son[Node]] || Max_Son[Node] == 0)
Max_Son[Node] = it;
}
}
int chains = 1;
void Split (int Node, int dad = -1) {
Id[Node] = chains;
Size_Id[chains]++;
if (Size[Node] == 1)
return;
Split(Max_Son[Node], Node);
for (auto it : G[Node]) {
if (it == dad || it == Max_Son[Node])
continue;
++ chains;
First[chains] = it;
Split(it, Node);
}
}
void Read () {
f >> N >> M;
for (int i = 1; i <= N; ++ i )
f >> val[i];
for (int i = 1; i < N; ++ i ) {
int x, y;
f >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
}
int Query (int X, int Y) {
if (Id[X] == Id[Y]) {
///Acelasi lant
int st = min(Level[X] - Level[First[Id[X]]] + 1, Level[Y] - Level[First[Id[X]]] + 1);
int dr = max(Level[X] - Level[First[Id[X]]] + 1, Level[Y] - Level[First[Id[X]]] + 1);
return Arbore[Id[X]]->Query(1, 1, Size_Id[Id[X]], st, dr);
}
if (Level[First[Id[X]]] < Level[First[Id[Y]]])
swap(X, Y);
int ans = Arbore[Id[X]]->Query(1, 1, Size_Id[Id[X]], 1, Level[X] - Level[First[Id[X]]] + 1);
return max(ans, Query(Dad[First[Id[X]]], Y));
}
void Init_Arbore () {
Arbore.push_back(new Aint(0));
for (int i = 1; i <= chains; ++ i )
Arbore.push_back(new Aint(Size_Id[i]));
for (int i = 1; i <= N; ++ i )
Arbore[Id[i]]->Update_Tree(1, 1, Size_Id[Id[i]], Level[i] - Level[First[Id[i]]] + 1, val[i]);
}
void Solve () {
for (; M; -- M ) {
int tip, x, y;
f >> tip >> x >> y;
if (tip == 0)
Arbore[Id[x]]->Update_Tree(1, 1, Size_Id[Id[x]], Level[x] - Level[First[Id[x]]] + 1, y);
else {
g << Query(x, y) << '\n';
}
}
}
int main () {
Read();
Dfs(1);
First[1] = 1;
Split(1);
Init_Arbore ();
Solve();
return 0;
}