#include <bits/stdc++.h>
using namespace std;
const int nmax = 1e5;
int sz[nmax + 1];
vector <int> g[nmax + 1];
vector <pair <int, int>> off[nmax + 1];
struct ura
{
int t, x, y, lca;
}q[nmax + 1];
int sef[nmax + 1];
int ef(int x)
{
if(x == sef[x])
return x;
return sef[x] = ef(sef[x]);
}
bool ok[nmax + 1];
void dfs(int nod, int t)
{
ok[nod] = 1;
for(auto x : off[nod])
{
if(ok[x.first])
q[x.second].lca = ef(x.first);
}
off[nod].clear();
sz[nod] = 1;
for(auto x : g[nod])
{
if(x != t)
{
dfs(x, nod);
sef[x] = nod;
sz[nod] += sz[x];
}
}
}
class SegmentTree
{
private:
int n;
vector <int> seg;
void pull(int nod)
{
int lnod = nod * 2, rnod = lnod + 1;
seg[nod] = max(seg[lnod], seg[rnod]);
}
void build(int nod, int st, int dr, vector <int> &v)
{
if(st == dr)
{
seg[nod] = v[st - 1];
return;
}
int mij = (st + dr) / 2, lnod = nod * 2, rnod = lnod + 1;
build(lnod, st, mij, v);
build(rnod, mij + 1, dr, v);
pull(nod);
}
void update(int nod, int st, int dr, int poz, int val)
{
if(st == dr)
{
seg[nod] = val;
return;
}
int mij = (st + dr) / 2, lnod = nod * 2, rnod = lnod + 1;
if(poz <= mij)
update(lnod, st, mij, poz, val);
else
update(rnod, mij + 1, dr, poz, val);
pull(nod);
}
void query(int nod, int st, int dr, int l, int r, int &rez)
{
if(l <= st && dr <= r)
{
rez = max(rez, seg[nod]);
return;
}
int mij = (st + dr) / 2, lnod = nod * 2, rnod = lnod + 1;
if(l <= mij)
query(lnod, st, mij, l, r, rez);
if(r > mij)
query(rnod, mij + 1, dr, l, r, rez);
}
public:
SegmentTree(vector <int> &v)
{
n = v.size();
seg.resize(n * 4 + 1);
build(1, 1, n, v);
}
void upd(int poz, int val)
{
update(1, 1, n, poz, val);
}
int qry(int l, int r)
{
int rez = 0;
query(1, 1, n, l, r, rez);
return rez;
}
void del()
{
seg.clear();
}
};
vector <SegmentTree> ab;
int t[nmax + 1], k;
struct ura2
{
int val, l, poz;
}v[nmax + 1];
void heavy(int nod, int tt)
{
int x = nod, y, maxi;
v[nod].l = ++k;
v[nod].poz = 1;
vector <int> lant;
lant.push_back(v[nod].val);
t[v[nod].l] = tt;
while(sz[x] > 1)
{
maxi = -1;
for(auto z : g[x])
{
if(sz[z] < sz[x] && sz[z] > maxi)
{
maxi = sz[z];
y = z;
}
}
lant.push_back(v[y].val);
v[y].l = v[x].l;
v[y].poz = v[x].poz + 1;
x = y;
}
SegmentTree abb(lant);
ab.push_back(abb);
x = nod;
lant.clear();
abb.del();
while(sz[x] > 1)
{
for(auto z : g[x])
{
if(sz[z] < sz[x] && !v[z].l)
heavy(z, x);
else
y = z;
}
x = y;
}
}
int solve(int x, int y)
{
if(v[x].l == v[y].l)
return ab[v[x].l - 1].qry(v[y].poz, v[x].poz);
else
return max(ab[v[x].l - 1].qry(1, v[x].poz), solve(t[v[x].l], y));
}
int main()
{
ios :: sync_with_stdio(false);
cin.tie(0);
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int n, i, x, m, y;
cin >> n >> m;
for(i = 1; i <= n; i++)
{
sef[i] = i;
cin >> v[i].val;
}
for(i = 1; i < n; i++)
{
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
for(i = 1; i <= m; i++)
{
cin >> q[i].t >> q[i].x >> q[i].y;
if(q[i].t)
{
off[q[i].x].push_back({q[i].y, i});
off[q[i].y].push_back({q[i].x, i});
}
}
dfs(1, 0);
heavy(1, 0);
for(i = 1; i <= m; i++)
{
if(q[i].t)
cout << max(solve(q[i].x, q[i].lca), solve(q[i].y, q[i].lca)) << '\n';
else
ab[v[q[i].x].l - 1].upd(v[q[i].x].poz, q[i].y);
}
return 0;
}