#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int Nmax = 100005;
class SegmentTree{
public:
SegmentTree(const int _n=0, vector<int> _vals=vector<int>()):
n(_n),
aint(vector<int>(5*_n+2)),
vals(_vals)
{
if(_n) Build(1, 1, n);
}
void update(const int poz, const int val)
{
X=poz;
Y=val;
Update(1, 1, n);
}
int query(const int st, const int dr)
{
ret=0;
X=st;
Y=dr;
Query(1, 1, n);
return ret;
}
private:
int n, X, Y, ret;
vector<int> aint, vals;
void Build(int nod, int l, int r)
{
if(l==r)
{
aint[nod]=vals[l];
return;
}
int mid=(l+r)/2;
Build(2*nod, l, mid);
Build(2*nod+1, mid+1, r);
aint[nod]=max(aint[2*nod], aint[2*nod+1]);
}
void Update(int nod, int l, int r)
{
if(l==r)
{
aint[nod]=Y;
return;
}
int mid=(l+r)/2;
if(X<=mid) Update(2*nod, l, mid);
else Update(2*nod+1, mid+1, r);
aint[nod]=max(aint[2*nod], aint[2*nod+1]);
}
void Query(int nod, int l, int r)
{
if(X<=l&&r<=Y)
{
if(aint[nod]>ret) ret=aint[nod];
return;
}
int mid=(l+r)/2;
if(X<=mid) Query(2*nod, l, mid);
if(Y>mid) Query(2*nod+1, mid+1, r);
}
};
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++)
{
Paths[i].push_back(0);
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.size() - 1, 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(1, Pos[x]));
x = Father[i];
i = Path[x];
}
else
{
Sol = max(Sol, STrees[j].query(1, 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);
}
}
}