#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int Nmax = 100005;
class SegmentTree {
public:
SegmentTree() {}
SegmentTree(vector<int> values)
{
for (N = 1; N < int(values.size()); N <<= 1);
Aint = vector<int> (2 * N + 3, 0);
for (int i = 0; i < int(values.size()); i++)
Aint[N + i] = values[i];
for (int i = N - 1; i; i--)
Aint[i] = max(Aint[2 * i], Aint[2 * i + 1]);
}
void update(int poz, const int val)
{
Aint[poz += N] = val;
for (poz >>= 1; poz; poz >>= 1)
Aint[poz] = max(Aint[2 * poz], Aint[2 * poz + 1]);
}
int query(int left, int right)
{
left += N;
right += N;
int ret = 0;
while (left <= right)
{
ret = max(ret, max(Aint[left], Aint[right]));
left = (left + 1) >> 1;
right = (right - 1) >> 1;
}
return ret;
}
private:
int N;
vector<int> Aint;
};
int A[Nmax], Path[Nmax], Nr[Nmax], Pos[Nmax], Lvl[Nmax], Father[Nmax];
vector<int> G[Nmax], Paths[Nmax], values;
int N, Nrpaths;
SegmentTree STrees[Nmax];
void Dfs1(const int node, const int father)
{
if (father) G[node].erase(find(G[node].begin(), G[node].end(), father));
Nr[node] = 1;
int noden = 0;
for (auto p: G[node])
{
Dfs1(p, node);
Nr[node] += Nr[p];
if (Nr[p] > Nr[noden])
noden = p;
}
if (!noden) Path[node] = ++Nrpaths;
else Path[node] = Path[noden];
Paths[Path[node]].push_back(node);
}
void Dfs2(const int node)
{
for (auto p: G[node])
{
if (Path[node] != Path[p])
{
Lvl[Path[p]] = Lvl[Path[node]] + 1;
Father[Path[p]] = node;
}
Dfs2(p);
}
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int Q;
scanf("%d%d", &N, &Q);
for (int i = 1; i <= N; i++)
scanf("%d", &A[i]);
for (int i = 1; i < N; i++)
{
int x, y;
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
Dfs1(1, 0);
for (int i = 1; i <= Nrpaths; i++)
{
reverse(Paths[i].begin(), Paths[i].end());
for (int j = 0; j < int(Paths[i].size()); j++)
{
Pos[Paths[i][j]] = j;
values.push_back(A[Paths[i][j]]);
}
STrees[i] = SegmentTree(values);
Paths[i].clear();
values.clear();
}
Dfs2(1);
while (Q--)
{
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (op == 0)
{
STrees[Path[x]].update(Pos[x], y);
}
else
{
int i = Path[x], j = Path[y], Sol = 0;
while (i != j)
{
if (Lvl[i] > Lvl[j])
{
Sol = max(Sol, STrees[i].query(0, Pos[x]));
x = Father[i];
i = Path[x];
}
else
{
Sol = max(Sol, STrees[j].query(0, Pos[y]));
y = Father[j];
j = Path[y];
}
Sol = max(Sol, STrees[i].query(min(Pos[x], Pos[y]), max(Pos[x], Pos[y])));
}
printf("%d\n", Sol);
}
}
}