#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
const int MAXN = 100100;
int depth[MAXN];
int sub[MAXN];
int value[MAXN];
int special[MAXN];
int first_pos[MAXN];
int last_pos[MAXN];
int rmq[20][4 * MAXN];
int path_id[MAXN];
int path_pos[MAXN];
int path_start[MAXN];
int order[MAXN];
int init_value[MAXN];
int aint[4 * MAXN];
int ln[MAXN];
int up_path[MAXN];
int father[MAXN];
vector<int> g[MAXN];
int n;
int counter = 0;
int path = 1;
int pos = 0;
int counter2 = 0;
void dfs(int node)
{
first_pos[node] = ++counter;
rmq[0][counter] = node;
int i = 0;
for (auto &it: g[node])
if (it != father[node])
{
father[it] = node;
depth[it] = depth[node] + 1;
dfs(it);
sub[node] += sub[it];
if (sub[it] > sub[i])
i = it;
rmq[0][++counter] = node;
last_pos[node] = counter;
}
if (i == 0)
sub[node] = 1;
else
special[node] = i;
}
void HLD(int node)
{
if (path_id[node] == 0)
path_id[node] = path;
path_pos[node] = ++pos;
order[node] = ++counter2;
init_value[counter2] = value[node];
if (special[node])
HLD(special[node]);
for (auto &it: g[node])
if (it != special[node] && it != father[node])
{
path++;
path_start[path] = counter2 + 1;
up_path[path] = node;
pos = 0;
HLD(it);
}
}
void buildTree(int i, int left, int right)
{
if (left == right)
{
aint[i] = init_value[left];
return;
}
int mid = (left + right) / 2;
buildTree(2 * i, left, mid);
buildTree(2 * i + 1, mid+1, right);
aint[i] = max(aint[2 * i], aint[2 * i + 1]);
}
int Min(int a, int b)
{
if (depth[a] < depth[b])
return a;
return b;
}
void initRMQ()
{
for (int i = 2; i <= counter; i++)
ln[i] = ln[i/2] + 1;
int lnn = ln[counter];
for (int i = 1; i <= lnn; i++)
for (int j = 1; j <= counter; j++)
{
if (j + (1<<i) > counter + 1)
break;
rmq[i][j] = Min(rmq[i-1][j], rmq[i-1][j + (1 << (i-1))]);
}
}
int lca(int a, int b)
{
int left = first_pos[a];
int right = first_pos[b];
if (left > right)
swap(left, right);
int l = ln[right - left + 1];
return Min(rmq[l][left], rmq[l][right - (1<<l) + 1]);
}
int qleft, qright, qval;
void update(int i, int left, int right)
{
if (right < qleft || left > qleft)
return;
if (left == right)
{
aint[i] = qval;
return;
}
int mid = (left + right) / 2;
update(2*i, left, mid);
update(2*i+1, mid+1, right);
aint[i] = max(aint[2*i], aint[2*i+1]);
}
int query_tree(int i, int left, int right)
{
if (right < qleft || left > qright)
return 0;
if (qleft <= left && right <= qright)
return aint[i];
int mid = (left + right) / 2;
return max(query_tree(2*i, left, mid), query_tree(2*i+1, mid+1, right));
}
int query_up(int u, int v)
{
int ans = 0;
while (path_id[u] != path_id[v])
{
qleft = path_start[path_id[u]];
qright = qleft + path_pos[u] - 1;
ans = max(ans, query_tree(1, 1, n));
u = up_path[path_id[u]];
}
qright = path_start[path_id[u]] + path_pos[u] - 1;
qleft = path_start[path_id[u]] + path_pos[v] - 1;
ans = max(ans, query_tree(1, 1, n));
return ans;
}
int query(int x, int y)
{
int l = lca(x, y);
return max(query_up(x, l), query_up(y, l));
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &value[i]);
for (int i = 1; i < n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1);
path_start[1] = 1;
HLD(1);
buildTree(1, 1, n);
initRMQ();
int t, x, y;
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d", &t, &x, &y);
if (t == 0)
{
qleft = order[x];
qval = y;
update(1, 1, n);
}
else
{
printf("%d\n", query(x, y));
}
}
return 0;
}