#include <fstream>
#include <climits>
#include <algorithm>
#include <vector>
#include <bitset>
using namespace std;
const string fn("heavypath");
ifstream in(fn + ".in");
ofstream out(fn + ".out");
#define cin in
#define cout out
const int MAX = 1e5;
int n, q, val[MAX + 5], niv[MAX + 5], w[MAX + 5], nrL, L[MAX + 5], Lfather[MAX + 5], Lniv[MAX + 5], Ldecal[MAX + 5];
int Tree[4 * MAX + 5];
vector<int> g[MAX + 5], Lant[MAX + 5];
bitset<MAX + 5> viz;
void dfs(int node)
{
viz[node] = 1;
w[node] = 1;
int leaf = 1, maxl = -1;
for (auto x : g[node])
{
if (viz[x])
continue;
leaf = 0;
niv[x] = niv[node] + 1;
dfs(x);
w[node] += w[x];
if (maxl == -1)
maxl = x;
else if (w[maxl] < w[x])
maxl = x;
}
if (leaf)
{
nrL++;
L[node] = nrL;
Lant[L[node]].push_back(node);
}
else
{
L[node] = L[maxl];
Lant[L[node]].push_back(node);
for (auto x : g[node])
{
if (x == maxl or niv[x] < niv[node])
continue;
Lfather[L[x]] = node;
Lniv[L[x]] = niv[node];
}
}
}
void build(int node, int l, int r, int decal, int pozl)
{
if (l == r)
Tree[node + decal] = val[Lant[pozl][l - 1]];
else
{
int m = (l + r) / 2;
build(2 * node, l, m, decal, pozl);
build(2 * node + 1, m + 1, r, decal, pozl);
Tree[node + decal] = max(Tree[2 * node + decal], Tree[2 * node + 1 + decal]);
}
}
void update(int node, int l, int r, int target, int val, int decal)
{
if (l == r)
Tree[node + decal] = val;
else
{
int m = (l + r) / 2;
if (target <= m)
update(2 * node, l, m, target, val, decal);
else
update(2 * node + 1, m + 1, r, target, val, decal);
Tree[node + decal] = max(Tree[2 * node + decal], Tree[2 * node + 1 + decal]);
}
}
int query(int node, int l, int r, int a, int b, int decal)
{
if (r < a or b < l)
return INT_MIN;
if (a <= l and r <= b)
return Tree[node + decal];
int m = (l + r) / 2;
return max(query(2 * node, l, m, a, b, decal), query(2 * node + 1, m + 1, r, a, b, decal));
}
void make_paths()
{
niv[1] = 1;
dfs(1);
for (int i = 1; i <= nrL; i++)
{
reverse(Lant[i].begin(), Lant[i].end());
if (i > 1)
Ldecal[i] = Ldecal[i - 1] + Lant[i - 1].size() * 4;
build(1, 1, Lant[i].size(), Ldecal[i], i);
}
}
void solve()
{
int t, x, y;
cin >> t >> x >> y;
if (t == 0)
update(1, 1, Lant[L[x]].size(), niv[x] - Lniv[L[x]], y, Ldecal[L[x]]);
else
{
int ans = INT_MIN;
while (1)
{
if (L[x] == L[y])
{
if (niv[x] > niv[y])
swap(x, y);
ans = max(ans, query(1, 1, Lant[L[x]].size(), niv[x] - Lniv[L[x]], niv[y] - Lniv[L[x]], Ldecal[L[x]]));
break;
}
if (Lniv[L[x]] < Lniv[L[y]])
swap(x, y);
ans = max(ans, query(1, 1, Lant[L[x]].size(), 1, niv[x] - Lniv[L[x]], Ldecal[L[x]]));
x = Lfather[L[x]];
}
cout << ans << '\n';
}
}
int main()
{
cin >> n >> q;
for (int i = 1; i <= n; i++)
cin >> val[i];
for (int i = 1, x, y; i < n; i++)
{
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
make_paths();
while (q--)
solve();
return 0;
}