#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
ifstream f("heavypath.in");
ofstream g("heavypath.out");
vector<int> aint, v, heavy, values(1), nodePos;
int N, Q;
void build(int x, int lx, int rx)
{
if (lx == rx)
{
if (lx <= N)
aint[x] = values[lx];
return;
}
int mid = (lx + rx) / 2;
build(2 * x, lx, mid);
build(2 * x + 1, mid + 1, rx);
aint[x] = max(aint[2 * x], aint[2 * x + 1]);
}
void update(int x, int lx, int rx, int poz, int val)
{
if (lx == rx)
{
aint[x] = val;
return;
}
int mid = (lx + rx) / 2;
if (poz <= mid)
{
update(2 * x, lx, mid, poz, val);
}
else
update(2 * x + 1, mid + 1, rx, poz, val);
aint[x] = max(aint[2 * x], aint[2 * x + 1]);
}
int query(int x, int lx, int rx, int l, int r)
{
if (rx < l || lx > r)
return 0;
if (lx >= l && rx <= r)
return aint[x];
int mid = (lx + rx) / 2;
return max(query(2 * x, lx, mid, l, r), query(2 * x + 1, mid + 1, rx, l, r));
}
vector<int> sz, pathHead, level, p;
void dfs(int node, int parent, const vector<vector<int>> &G)
{
sz[node] = 1;
p[node] = parent;
int szChildMax = 0, childMax = 0;
for (auto child: G[node])
{
if (child == parent)
continue;
level[child] = level[node] + 1;
dfs(child, node, G);
if (sz[child] > szChildMax)
{
szChildMax = sz[child];
childMax = child;
}
sz[node] += sz[child];
}
heavy[node] = childMax;
}
void decompose(int node, int crtHead, const vector<vector<int>> &G)
{
pathHead[node] = crtHead;
nodePos[node] = values.size();
values.push_back(v[node]);
if (heavy[node] != 0)
{
decompose(heavy[node], crtHead, G);
}
for (auto child: G[node])
{
if (child != heavy[node] && child != p[node])
{
decompose(child, child, G);
}
}
}
int main()
{
f >> N >> Q;
vector<vector<int>> G(N + 1);
aint.resize(4 * N, 0);
heavy.resize(N + 1, 0);
v.reserve(N + 1);
level.reserve(N + 1);
pathHead.reserve(N + 1);
p.reserve(N + 1);
nodePos.reserve(N + 1);
for (int i = 1; i <= N; i++)
{
f >> v[i];
}
for (int i = 1; i < N; i++)
{
int x, y;
f >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
sz.reserve(N + 1);
dfs(1, 0, G);
decompose(1, 1, G);
build(1, 1, N);
while (Q--)
{
int tip, x, y;
f >> tip >> x >> y;
if (tip == 0)
{
update(1, 1, N, nodePos[x], y);
}
else
{
int mxCrt = 0;
for (; pathHead[x] != pathHead[y]; x = p[pathHead[x]])
{
if (level[x] < level[y])
swap(x, y);
mxCrt = max(mxCrt, query(1, 1, N, nodePos[pathHead[x]], nodePos[x]));
}
if (level[x] > level[y])
swap(x, y);
mxCrt = max(mxCrt, query(1, 1, N, nodePos[x], nodePos[y]));
g << mxCrt << '\n';
}
}
return 0;
}