#include <bits/stdc++.h>
using namespace std;
ifstream fin ("heavypath.in");
ofstream fout ("heavypath.out");
int n, m;
int v[100001];
vector <int> g[100001];
int tata[100001], sz[100001], ad[100001], head[100001], greu[100001], poz[100001], invpoz[100001], timer;
struct arb_int
{
int aint[400001];
void build(int node, int l, int r)
{
if (l == r)
{
aint[node] = v[invpoz[l]];
return;
}
int mid = (l + r) / 2;
build(2 * node, l, mid);
build(2 * node + 1, mid + 1, r);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
void update(int node, int poz, int val, int l, int r)
{
if (l > poz || r < poz)
return;
if (l == r)
{
aint[node] = val;
return;
}
int mid = (l + r) / 2;
update(2 * node, poz, val, l, mid);
update(2 * node + 1, poz, val, mid + 1, r);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
void update(int poz, int val)
{
update(1, poz, val, 1, n);
}
int query(int node, int l, int r, int ql, int qr)
{
if (r < ql || l > qr)
return 0;
if (l >= ql && r <= qr)
return aint[node];
int mid = (l + r) / 2;
return max(query(2 * node, l, mid, ql, qr), query(2 * node + 1, mid + 1, r, ql, qr));
}
int query(int l, int r)
{
return query(1, 1, n, l, r);
}
} aint;
void dfs1(int node, int parent)
{
sz[node] = 1;
int best = 0;
for (auto vecin : g[node])
if (vecin != parent)
{
tata[vecin] = node;
ad[vecin] = ad[node] + 1;
dfs1(vecin, node);
sz[node] += sz[vecin];
if (sz[vecin] > best)
{
greu[node] = vecin;
best = sz[vecin];
}
}
}
void dfs2(int node, int h)
{
head[node] = h;
poz[node] = ++timer;
invpoz[timer] = node;
if (greu[node] != -1)
dfs2(greu[node], h);
for (auto vecin : g[node])
if (vecin != tata[node] && vecin != greu[node])
dfs2(vecin, vecin);
}
int query_path(int x, int y)
{
int ans = 0;
while (head[x] != head[y])
{
if (ad[head[x]] < ad[head[y]])
swap(x, y);
ans = max(ans, aint.query(poz[head[x]], poz[x]));
x = tata[head[x]];
}
if (ad[x] > ad[y])
swap(x, y);
ans = max(ans, aint.query(poz[x], poz[y]));
return ans;
}
void update_node(int u, long long x)
{
aint.update(poz[u], x);
}
int main()
{
fin >> n >> m;
for (int i = 1; i <= n; i++)
{
fin >> v[i];
greu[i] = -1;
}
for (int i = 1; i <= n - 1; i++)
{
int x, y;
fin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(1, 0);
dfs2(1, 1);
aint.build(1, 1, n);
for (int i = 1; i <= m; i++)
{
int t, x, y;
fin >> t >> x >> y;
if (t == 0)
update_node(x, y);
else
fout << query_path(x, y) << '\n';
}
return 0;
}