#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;
struct Path
{
int size, p;
int f;
Path(int size, int p, int f) : size(size), p(p), f(f)
{
}
int firstElem()
{
return f;
}
};
int n, m;
int v[nmax];
int depth[nmax];
int parent[lgmax][nmax];
int pIndex[nmax];
vector<int> adj[nmax];
vector<Path> paths;
int aint[3 * nmax];
int aintIndex[nmax];
void update(int poz, int val, int st = 1, int dr = n, int nod = 1)
{
if (st == dr)
{
aint[nod] = val;
}
else
{
int mid = (st + dr) / 2;
if (poz <= mid)
{
update(poz, val, st, mid, 2 * nod);
}
else
{
update(poz, val, mid + 1, dr, 2 * nod + 1);
}
aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
}
int query(int l, int r, int st = 1, int dr = n, int nod = 1)
{
if (l == st && r == dr)
{
return aint[nod];
}
else
{
int mid = (st + dr) / 2;
if (r <= mid)
return query(l, r, st, mid, 2 * nod);
else if (mid < l)
return query(l, r, mid + 1, dr, 2 * nod + 1);
else
{
return max(
query(l, mid, st, mid, 2 * nod),
query(mid + 1, r, mid + 1, dr, 2 * nod + 1));
}
}
}
int ind = 1;
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.back()));
for (auto j : i)
{
pIndex[j] = paths.size() - 1;
aintIndex[j] = ind++;
}
}
}
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)
{
//cerr << sus << '\n';
int ans = 0;
while (1)
{
if (depth[paths[pIndex[jos]].firstElem()] <= depth[sus])
{
//cerr << sus << ' ' << jos << '\n';
ans = max(ans, query(aintIndex[jos], aintIndex[sus]));
//cerr << "->" << ans << '\n';
break;
}
else
{
//cerr << paths[pIndex[jos]].firstElem() << ' ' << jos << '\n';
ans = max(ans, query(aintIndex[jos], aintIndex[paths[pIndex[jos]].firstElem()]));
jos = paths[pIndex[jos]].p;
//cerr << "->" << ans << '\n';
}
}
return ans;
}
void solve()
{
for (int i = 1; i <= n; i++)
{
update(aintIndex[i], v[i]);
}
for (int i = 0; i < m; i++)
{
int t, x, y;
in >> t >> x >> y;
if (t == 0)
{
v[x] = y;
update(aintIndex[x], y);
}
else
{
int p = lca(x, y);
//out << max(q(p, x), q(p, y)) << '\n';
}
}
}
int main()
{
readInput();
auto i = dfs();
paths.push_back(Path(i.size(), 0, i.back()));
for (auto j : i)
{
pIndex[j] = paths.size() - 1;
aintIndex[j] = ind++;
}
solve();
}