#include <cstdio>
#include <vector>
#include <algorithm>
#define MAXN 100001
int N, M;
bool visited[MAXN];
int v[MAXN], parent[MAXN], level[MAXN], subtree_size[MAXN];
int path[MAXN], path_parent[MAXN], last_path;
int segtree[4*MAXN], st_offsets[MAXN];
std::vector<int> neigh[MAXN], paths[MAXN];
void dfs(int nod)
{
int heaviest_child = -1;
visited[nod] = 1;
subtree_size[nod] = 1;
for (auto it = neigh[nod].begin(); it != neigh[nod].end(); ++it)
{
if (visited[*it])
{
continue;
}
level[*it] = level[nod] + 1;
visited[*it] = 1;
dfs(*it);
subtree_size[nod] += subtree_size[*it];
if (-1 == heaviest_child || subtree_size[*it] > subtree_size[heaviest_child])
{
heaviest_child = *it;
}
}
if (-1 == heaviest_child)
{
path[nod] = ++last_path;
paths[last_path].push_back(nod);
}
else
{
path[nod] = path[heaviest_child];
paths[path[nod]].push_back(nod);
for (auto it = neigh[nod].begin(); it != neigh[nod].end(); ++it)
{
if (*it == heaviest_child || level[*it] < level[nod])
{
continue;
}
path_parent[path[*it]] = nod;
}
}
}
void build_segtree(int nd, int left, int right, int offset, int path)
{
if (left == right)
{
segtree[nd + offset] = v[paths[path][left - 1]];
}
else
{
int mid = (left+right)/2;
build_segtree(nd*2, left, mid, offset, path);
build_segtree(nd*2+1, mid+1, right, offset, path);
segtree[nd + offset] = std::max(segtree[nd*2+offset], segtree[nd*2+1+offset]);
}
}
void update(int nd, int left, int right, int pos, int val, int offset)
{
if (left == right)
{
segtree[nd + offset] = val;
}
else
{
int mid = (left+right)/2;
if (pos <= mid)
{
update(2*nd, left, mid, pos, val, offset);
}
else
{
update(2*nd+1, mid+1, right, pos, val, offset);
}
segtree[nd + offset] = std::max(segtree[2*nd+offset], segtree[2*nd+1+offset]);
}
}
int query(int nd, int left, int right, int qleft, int qright, int offset)
{
int ans = 0;
if (left >= qleft && right <= qright)
{
ans = segtree[nd + offset];
}
else
{
int mid = (left+right)/2;
if (qleft <= mid)
{
ans = query(nd*2, left, mid, qleft, qright, offset);
}
if (qright > mid)
{
ans = std::max(ans, query(nd*2+1, mid+1, right, qleft, qright, offset));
}
}
return ans;
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; ++i)
{
scanf("%d", &v[i]);
}
for (int i = 0; i < N-1; ++i)
{
int a, b;
scanf("%d%d", &a, &b);
neigh[a].push_back(b);
neigh[b].push_back(a);
}
level[1] = 1;
dfs(1);
for (int i = 1; i <= last_path; ++i)
{
reverse(paths[i].begin(), paths[i].end());
if (i > 1)
{
st_offsets[i] = st_offsets[i-1] + paths[i-1].size() * 4;
}
build_segtree(1, 1, paths[i].size(), st_offsets[i], i);
}
for (int i = 0; i < M; ++i)
{
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if (t == 0)
{
update(1,1,paths[path[x]].size(), level[x]-level[paths[path[x]][0]]+1,
y, st_offsets[path[x]]);
}
else
{
int sol = 0;
while (true)
{
if (path[x] == path[y])
{
if (level[x] > level[y])
{
std::swap(x,y);
}
sol = std::max(sol, query(1, 1, paths[path[x]].size(),
level[x] - level[paths[path[x]][0]] + 1,
level[y] - level[paths[path[x]][0]] + 1,
st_offsets[path[x]]));
break;
}
if (level[paths[path[x]][0]] < level[paths[path[y]][0]])
{
std::swap(x, y);
}
sol = std::max(sol, query(1, 1, paths[path[x]].size(), 1,
level[x] - level[paths[path[x]][0]] + 1,
st_offsets[path[x]]));
x = path_parent[path[x]];
}
printf("%d\n", sol);
}
}
return 0;
}