#include <fstream>
#include <vector>
using namespace std;
ifstream cin ("heavypath.in");
ofstream cout ("heavypath.out");
#define pb push_back
#define ll int
const int NMAX = 100005;
const int N2 = 20;
vector <int> g[NMAX];
ll seg[4 * NMAX];
ll sz[NMAX];
ll heavy_child[NMAX];
ll label[NMAX];
ll depth[NMAX];
ll lift[N2][NMAX];
ll chain[NMAX];
ll a[NMAX];
ll dad[NMAX];
ll n;
ll combine(ll a, ll b)
{
return max(a, b);
}
void update(int nod, int l, int r, int poz, int val)
{
if (l == r)
{
seg[nod] = val;
return;
}
int mid = (l + r) / 2, ls = 2 * nod, rs = ls + 1;
if (poz <= mid)
update(ls, l, mid, poz, val);
else
update(rs, mid + 1, r, poz, val);
seg[nod] = combine(seg[ls], seg[rs]);
}
ll query(int nod, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr)
return seg[nod];
if (l > r || r < ql || qr < l)
return 0;
int mid = (l + r) / 2, ls = 2 * nod, rs = ls + 1;
ll a = query(ls, l, mid, ql, qr);
ll b = query(rs, mid + 1, r, ql, qr);
return combine(a, b);
}
void subarb(int nod)
{
sz[nod] = 1;
int maxi = -1;
for (int i = 0; i < g[nod].size(); i++)
{
int x = g[nod][i];
if (dad[x])
continue;
dad[x] = nod;
lift[0][x] = nod;
depth[x] = depth[nod] + 1;
subarb(x);
sz[nod] += sz[x];
if (maxi == -1)
maxi = x;
else
if (sz[x] > sz[maxi])
maxi = x;
}
heavy_child[nod] = maxi;
}
void lifting()
{
for (int i = 1; i < N2; i++)
for (int j = 1; j <= n; j++)
lift[i][j] = lift[i - 1][lift[i - 1][j]];
}
int LCA(int x, int y)
{
int lg = N2 - 1;
while (depth[x] < depth[y])
{
if (depth[x] <= depth[lift[lg][y]])
y = lift[lg][y];
lg--;
}
lg = N2 - 1;
while (depth[x] > depth[y])
{
if (depth[y] <= depth[lift[lg][x]])
x = lift[lg][x];
lg--;
}
lg = N2 - 1;
while (x != y && lg > -1)
{
if(lift[lg][x] != lift[lg][y])
{
x = lift[lg][x];
y = lift[lg][y];
}
lg--;
}
if (x != y)
return lift[0][x];
return x;
}
void compute_chains(int nod)
{
if (heavy_child[nod] != -1)
chain[heavy_child[nod]] = chain[nod];
for (int i = 0; i < g[nod].size(); i++)
{
int x = g[nod][i];
if (x != dad[nod])
compute_chains(x);
}
}
int timp = 0;
void compute_labels(int nod)
{
label[nod] = ++timp;
update(1, 1, n, timp, a[nod]);
if (heavy_child[nod] != -1)
compute_labels(heavy_child[nod]);
for (int i = 0; i < g[nod].size(); i++)
{
int x = g[nod][i];
if (x != dad[nod] && x != heavy_child[nod])
compute_labels(x);
}
}
ll p2[N2];
int up(int x, int dist)
{
for (int i = N2; i > -1; i--)
{
if (p2[i] <= dist)
{
dist -= p2[i];
x = lift[i][x];
}
}
return x;
}
ll query_chain(int x, int y)
{
ll val = 0;
while (depth[y] <= depth[x])
{
int boss = chain[x];
if (depth[boss] < depth[y])
{
int dist = depth[x] - depth[y];
boss = up(x, dist);
}
val = combine(val, query(1, 1, n, label[boss], label[x]));
x = dad[boss];
}
return val;
}
int main()
{
int i, q;
cin >> n >> q;
for (i = 1; i <= n; i++)
{
cin >> a[i];
chain[i] = i;
}
for (i = 1; i < n; i++)
{
int x, y;
cin >> x >> y;
g[x].pb(y);
g[y].pb(x);
}
dad[1] = -1;
depth[1] = 1;
subarb(1);
lifting();
compute_chains(1);
compute_labels(1);
p2[0] = 1;
for (i = 1; i < N2; i++)
p2[i] = 2 * p2[i - 1];
while (q--)
{
int tip, x, y;
cin >> tip;
tip++;
if (tip == 1)
{
cin >> x >> y;
update(1, 1, n, label[x], y);
continue;
}
cin >> x>> y;
int lca = LCA(x, y);
cout << combine(query(1, 1, n, label[lca], label[lca]), combine(query_chain(x, lca), query_chain(y, lca))) << '\n';
//cout << query_chain(x, 1) <<'\n';
}
return 0;
}