#include <bits/stdc++.h>
// #define in cin
// #define out cout
using namespace std;
ifstream in("heavypath.in");
ofstream out("heavypath.out");
const int nmax = 1e5 + 5e0;
const int lgmax = 18;
int n, m;
int v[nmax];
int lIndex[nmax];
int ppoz[nmax];
int depth[nmax];
int parent[lgmax][nmax];
struct aint
{
int val;
aint *pst, *pdr;
aint(int val = 0) : val(val)
{
pst = pdr = nullptr;
}
aint *getSt()
{
if (pst == nullptr)
pst = new aint();
return pst;
}
aint *getDr()
{
if (pdr == nullptr)
pdr = new aint();
return pdr;
}
int stVal()
{
if (pst == nullptr)
return 0;
return pst->val;
}
int drVal()
{
if (pdr == nullptr)
return 0;
return pdr->val;
}
void update(int poz, int vall, int st, int dr)
{
if (st == dr)
{
val = vall;
}
else
{
int mid = (st + dr) / 2;
if (poz <= mid)
{
getSt()->update(poz, vall, st, mid);
}
else
{
getDr()->update(poz, vall, mid + 1, dr);
}
val = max(stVal(), drVal());
}
}
int query(int l, int r, int st, int dr, int nod = 1)
{
if (this == nullptr)
return 0;
if (l == st && r == dr)
{
return val;
}
else
{
int mid = (st + dr) / 2;
if (r <= mid)
{
return pst->query(l, r, st, mid);
}
else if (mid < l)
{
return pdr->query(l, r, mid + 1, dr);
}
else
{
return max(pst->query(l, mid, st, mid), pdr->query(mid + 1, r, mid + 1, dr));
}
}
}
void debug(int st, int dr)
{
if (this == nullptr)
cerr << 0 << '\n';
else
{
cerr << st << ' ' << dr << ' ' << val << '\n';
pst->debug(st, (st + dr) / 2);
pdr->debug((st + dr) / 2 + 1, dr);
}
}
};
struct Path
{
int size, p;
aint *arb;
vector<int> vec;
Path(int size, int p, vector<int> v) : size(size), p(p)
{
reverse(v.begin(), v.end());
vec = v;
for (int ind = 0; ind < vec.size(); ind++)
{
ppoz[vec[ind]] = ind;
}
arb = new aint();
}
void update(int ind)
{
arb->update(ppoz[ind], v[ind], 0, size - 1);
}
int query(int l, int r)
{
return arb->query(l, r, 0, size - 1);
}
int firstElem()
{
return vec[0];
}
void debug()
{
for (auto i : vec)
{
cerr << i << ' ';
}
cerr << '\n';
for (auto i : vec)
{
cerr << v[i] << ' ';
}
cerr << '\n';
arb->debug(0, size - 1);
}
};
vector<int> adj[nmax];
vector<Path> paths;
vector<int> dfs(int nod = 1, int p = 0, int dep = 0)
{
depth[nod] = dep;
parent[0][nod] = p;
for (int i = 1; i < lgmax; i++)
{
parent[i][nod] = parent[i - 1][parent[i - 1][nod]];
}
vector<int> path;
vector<vector<int>> tmm;
int maxx = 0;
for (auto i : adj[nod])
{
if (i != p)
{
auto tm = dfs(i, nod, dep + 1);
tmm.push_back(tm);
maxx = max(maxx, (int)tm.size());
}
}
bool found = 0;
for (auto i : tmm)
{
if (i.size() == maxx && found == 0)
{
path = i;
found = 1;
}
else
{
paths.push_back(Path(i.size(), nod, i));
for (auto j : i)
{
lIndex[j] = paths.size() - 1;
}
}
}
path.push_back(nod);
return path;
}
void readInput()
{
in >> n >> m;
for (int i = 1; i <= n; i++)
{
in >> v[i];
}
for (int i = 1; i < n; i++)
{
int a, b;
in >> a >> b;
adj[a].push_back(b);
adj[b].push_back(a);
}
}
int lca(const int a, const int b)
{
int ta = a, tb = b;
if (depth[a] > depth[b])
{
int diff = depth[a] - depth[b];
for (int i = 0, bit = 1; i < lgmax; i++, bit <<= 1)
{
if (diff & bit)
{
diff -= bit;
ta = parent[i][ta];
}
}
}
else if (depth[b] > depth[a])
{
int diff = depth[b] - depth[b];
for (int i = 0, bit = 1; i < lgmax; i++, bit <<= 1)
{
if (diff && bit)
{
diff -= bit;
tb = parent[i][tb];
}
}
}
if (ta == tb)
return ta;
for (int i = 0; i < lgmax; i++)
{
if (parent[i][ta] != parent[i][tb])
{
ta = parent[i][ta];
tb = parent[i][tb];
}
}
return parent[0][ta];
}
int q(const int sus, int jos)
{
int ans = 0;
while (1)
{
if (depth[paths[lIndex[jos]].firstElem()] <= depth[sus])
{
ans = max(ans, paths[lIndex[jos]].query(ppoz[sus], ppoz[jos]));
break;
}
else
{
ans = max(ans, paths[lIndex[jos]].query(0, ppoz[jos]));
jos = paths[lIndex[jos]].p;
}
}
return ans;
}
void solve()
{
for (int i = 1; i <= n; i++)
{
paths[lIndex[i]].update(i);
}
for (int i = 0; i < m; i++)
{
int t, x, y;
in >> t >> x >> y;
if (t == 0)
{
v[x] = y;
paths[lIndex[x]].update(x);
}
else
{
int p = lca(x, y);
out << max(q(p, x), q(p, y)) << '\n';
}
}
}
int main()
{
readInput();
auto i = dfs();
for (int ind = 0; ind < i.size(); ind++)
{
ppoz[i[ind]] = ind;
}
paths.push_back(Path(i.size(), 0, i));
for (auto j : i)
{
lIndex[j] = paths.size() - 1;
}
solve();
}