// solutie care foloseste longest path decomposition
using namespace std;
#ifdef EZ
#include "./ez/ez.h"
const string FILE_NAME = "test";
#else
#include <bits/stdc++.h>
const string FILE_NAME = "heavypath";
#endif
#define mp make_pair
#define mt make_tuple
#define ll long long
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define cin fin
#define cout fout
ifstream fin (FILE_NAME + ".in");
ofstream fout (FILE_NAME + ".out");
const int nMAX = 100e3;
int n, m;
vector<int> v(nMAX + 1);
vector<int> gf[nMAX + 1];
int tat[nMAX + 1];
int niv[nMAX + 1];
int e[2*nMAX], k;
int rmq[17+1][2*nMAX];
int st[nMAX + 1];
int lung[nMAX + 1]; // lung[i] = lungimea celui mai lung lant de la i in jos
int nex[nMAX + 1]; // nex[i] = fiul care duce la aceasta lungime (lung[i])
vector<int> path[nMAX + 1];
int pathSize[nMAX + 1];
vector<int> aint[nMAX + 1];
int firstNodeInPath[nMAX + 1];
void dfs(int nod, int dad = 0)
{
niv[nod] = niv[dad] + 1;
tat[nod] = dad;
e[++k] = nod;
st[nod] = k;
for (int fiu : gf[nod])
{
if (fiu == dad)
continue;
dfs(fiu, nod);
e[++k] = nod;
if (lung[fiu] + 1 > lung[nod])
{
lung[nod] = lung[fiu] + 1;
nex[nod] = fiu;
}
}
}
void dfsDecompose(int nod, vector<int> &p, int dad = 0)
{
p.pb(nod);
for (int fiu : gf[nod])
{
if (fiu == dad)
continue;
if (nex[nod] == fiu)
{
firstNodeInPath[fiu] = firstNodeInPath[nod];
dfsDecompose(fiu, p, nod);
}
else
{
firstNodeInPath[fiu] = fiu;
dfsDecompose(fiu, path[fiu], nod);
}
}
}
void buildAint(int which, int nod, int st, int dr)
{
vector<int> &Aint = aint[which];
vector<int> &V = path[which];
if (st == dr)
return (void) (Aint[nod] = v[V[st-1]]);
int mj = st+dr >> 1;
buildAint(which, nod<<1, st, mj);
buildAint(which, nod<<1|1, mj+1, dr);
Aint[nod] = max(Aint[nod<<1], Aint[nod<<1|1]);
}
int queryAint(vector<int> &aint, int nod, int st, int dr, int qst, int qdr)
{
if (qst <= st && dr <= qdr)
return aint[nod];
int mj = st+dr >> 1;
int ans = 0;
if (qst <= mj)
ans = max(ans, queryAint(aint, nod<<1, st, mj, qst, qdr));
if (mj+1 <= qdr)
ans = max(ans, queryAint(aint, nod<<1|1, mj+1, dr, qst, qdr));
return ans;
}
void updateAint(vector<int> &aint, int nod, int st, int dr, int qpos, int qval)
{
if (st == dr)
return (void) (aint[nod] = qval);
int mj = st+dr >> 1;
if (qpos <= mj)
updateAint(aint, nod<<1, st, mj, qpos, qval);
else
updateAint(aint, nod<<1|1, mj+1, dr, qpos, qval);
aint[nod] = max(aint[nod<<1], aint[nod<<1|1]);
}
void genRMQ()
{
for (int i = 1; i < 2*n; ++i)
rmq[0][i] = e[i];
for (int j = 1; (1<<j) < 2*n; ++j)
for (int i = 1; i-1 + (1<<j) < 2*n; ++i)
{
int a = rmq[j-1][i];
int b = rmq[j-1][i + (1<<j-1)];
if (niv[a] <= niv[b])
rmq[j][i] = a;
else
rmq[j][i] = b;
}
}
int queryRMQ(int l, int r)
{
int log = 31 - __builtin_clz(r-l+1);
int a = rmq[log][l];
int b = rmq[log][r+1 - (1<<log)];
if (niv[a] <= niv[b])
return a;
return b;
}
int LCA(int x, int y)
{
if (st[x] > st[y])
return queryRMQ(st[y], st[x]);
return queryRMQ(st[x], st[y]);
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)
cin >> v[i];
for (int i = 1; i < n; ++i)
{
int a, b;
cin >> a >> b;
gf[a].pb(b);
gf[b].pb(a);
}
dfs(1);
genRMQ();
firstNodeInPath[1] = 1;
dfsDecompose(1, path[1]);
v.clear();
for (int i = 1; i <= n; ++i)
{
gf[i].clear();
if (path[i].empty())
continue;
aint[i].resize(4 * path[i].size());
buildAint(i, 1, 1, path[i].size());
pathSize[i] = path[i].size();
path[i].clear();
}
while (m--)
{
int op, x, y;
cin >> op >> x >> y;
if (op == 0)
{
int first = firstNodeInPath[x];
updateAint(aint[first], 1, 1, pathSize[first], niv[x] - niv[first] + 1, y);
}
else if (op == 1)
{
int lca = LCA(x, y);
auto solve = [&](int x, int y) -> int { // x e stramos al lui y
int ans = 0;
while (y)
{
int first = firstNodeInPath[y];
if (niv[first] >= niv[x])
{
ans = max(ans, queryAint(aint[first], 1, 1, pathSize[first],
1, niv[y] - niv[first] + 1));
y = tat[first];
}
else
{
ans = max(ans, queryAint(aint[first], 1, 1, pathSize[first],
niv[x] - niv[first] + 1, niv[y] - niv[first] + 1));
y = 0;
}
}
return ans;
};
if (lca != x && lca != y)
cout << max(solve(lca, x), solve(lca, y)) << '\n';
else if (niv[x] <= niv[y])
cout << solve(x, y) << '\n';
else
cout << solve(y, x) << '\n';
}
}
}