#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define MAXN 100050
using namespace std;
int n, m;
int v[MAXN];
vector<int> graf[MAXN];
int parent[MAXN], lparent[MAXN], depth[MAXN];
int nq;
int lweight[MAXN], core[MAXN], rel[MAXN];
vector<int> lanturi[MAXN];
struct SegmentTree
{
int *a;
int sz;
SegmentTree(int ind)
{
sz = lanturi[ind].size()-1;
a = new int[sz*4];
init(1, sz, 1, ind);
}
void init(int st, int dr, int nod, int ind)
{
if (st == dr) {
a[nod] = v[lanturi[ind][st]];
return;
}
int mid = (st+dr)>>1;
init(st, mid, nod<<1, ind);
init(mid+1, dr, nod<<1 | 1, ind);
a[nod] = max(a[nod<<1], a[nod<<1 | 1]);
}
void update(int pos, int val)
{
update(pos, val, 1, sz, 1);
}
int getMax(int qst, int qdr)
{
return getMax(qst, qdr, 1, sz, 1);
}
void update(int pos, int val, int st, int dr, int nod)
{
if (st == dr) {
a[nod] = val;
return;
}
int mid = (st + dr) >> 1;
if (pos <= mid)
update(pos, val, st, mid, nod<<1);
else
update(pos, val, mid+1, dr, nod << 1 | 1);
a[nod] = max(a[nod<<1], a[nod<<1 | 1]);
}
int getMax(int qst, int qdr, int st, int dr, int nod)
{
if (qst <= st && dr <= qdr)
return a[nod];
int mid = (st + dr) >> 1;
int maxi = -1;
if (qst <= mid)
maxi = max(maxi, getMax(qst, qdr, st, mid, nod<<1));
if (qdr > mid)
maxi = max(maxi, getMax(qst, qdr, mid+1, dr, nod<<1 | 1));
return maxi;
}
}*aint[MAXN];
void read()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &v[i]);
int x, y;
for (int i = 1; i <= n-1; i++) {
scanf("%d %d", &x, &y);
graf[x].push_back(y);
graf[y].push_back(x);
}
}
void build(int nod, int d)
{
depth[nod] = d;
int maxi = -1, pos;
for (int y : graf[nod]) {
if (depth[y]) continue;
parent[y] = nod;
build(y, d+1);
if (lweight[core[y]] > maxi) {
maxi = lweight[core[y]];
pos = core[y];
}
}
if (maxi == -1)
core[nod] = ++nq;
else
core[nod] = pos;
lanturi[core[nod]].push_back(nod);
lweight[core[nod]]++;
for (int y : graf[nod])
if (parent[y] == nod && core[y] != core[nod])
lparent[core[y]] = nod;
}
void diapazon()
{
for (int i = 1; i <= nq; i++) {
lanturi[i].push_back(-1);
std::reverse(lanturi[i].begin(), lanturi[i].end());
for (int j = 1, t = lanturi[i].size(); j < t; j++)
rel[lanturi[i][j]] = j;
aint[i] = new SegmentTree(i);
}
}
void update(int x, int y)
{
aint[core[x]]->update(rel[x], y);
}
int query(int x, int y)
{
if (core[x] == core[y])
return aint[core[x]]->getMax(min(rel[x], rel[y]), max(rel[x], rel[y]));
if (depth[lanturi[core[x]][1]] > depth[lanturi[core[y]][1]])
swap(x, y);
return max(aint[core[y]]->getMax(1, rel[y]), query(x, lparent[core[y]]));
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
read();
build(1, 1);
diapazon();
for (int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d %d %d", &t, &x, &y);
if (t == 0)
update(x, y);
else
printf("%d\n", query(x, y));
}
return 0;
}