#define MAX_N 100000
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
struct interval_tree
{
int count{}, previous{};
vector<int> data{};
int get(int node, int left, int right, int qleft, int qright)
{
if ((qleft <= left) && (right <= qright))
return data[node];
else
{
int middle = (left + right) >> 1, max_value = 0;
if (qleft <= middle)
max_value = get(node << 1, left, middle, qleft, qright);
if (qright > middle)
max_value = max(max_value, get(node << 1 | 1, middle + 1, right, qleft, qright));
return max_value;
}
}
void set(int node, int left, int right, int index, int value)
{
if (left == right)
data[node] = value;
else
{
int middle = (left + right) >> 1;
if (index <= middle)
set(node << 1, left, middle, index, value);
else
set(node << 1 | 1, middle + 1, right, index, value);
data[node] = max(data[node << 1], data[node << 1 | 1]);
}
}
};
int n, m, v[MAX_N + 1], l[MAX_N + 1], t[2][MAX_N + 1];
vector<interval_tree> d;
vector<int> g[MAX_N + 1];
int decompose(int node = 1, int previous = 0, int level = 1)
{
l[node] = level;
int sum = 1, sum_max = 0, node_max = 0;
for (int next : g[node])
{
if (next != previous)
{
int sum_next = decompose(next, node, level + 1);
sum += sum_next;
if (sum_max < sum_next)
{
sum_max = sum_next;
node_max = next;
}
else
{
int log2;
for (log2 = 0; (1 << log2) < t[1][next]; ++log2);
d[t[0][next]].count = t[1][next];
d[t[0][next]].previous = node;
d[t[0][next]].data = vector<int>(1 << (log2 + 1), 0);
}
}
}
if (sum == 1)
{
t[0][node] = d.size();
t[1][node] = 1;
d.push_back(interval_tree());
}
else
{
t[0][node] = t[0][node_max];
t[1][node] = t[1][node_max] + 1;
}
if (node == 1)
{
int log2;
for (log2 = 0; (1 << log2) <= t[1][node]; ++log2);
d[t[0][node]].count = t[1][node];
d[t[0][node]].previous = 0;
d[t[0][node]].data = vector<int>(1 << (log2 + 1), 0);
for (int i = 1; i <= n; ++i)
d[t[0][i]].set(1, 1, d[t[0][i]].count, t[1][i], v[i]);
}
return sum;
}
int max_on_path(int x, int y)
{
int maxx = v[x], maxy = v[y];
while (t[0][x] != t[0][y])
{
if (l[d[t[0][x]].previous] > l[d[t[0][y]].previous])
{
maxx = max(maxx, d[t[0][x]].get(1, 1, d[t[0][x]].count, t[1][x], d[t[0][x]].count));
x = d[t[0][x]].previous;
}
else
{
maxy = max(maxy, d[t[0][y]].get(1, 1, d[t[0][y]].count, t[1][y], d[t[0][y]].count));
y = d[t[0][y]].previous;
}
}
if (l[x] < l[y])
x ^= y ^= x ^= y;
return max(d[t[0][x]].get(1, 1, d[t[0][x]].count, t[1][x], t[1][y]), max(maxx, maxy));
}
int main()
{
fin >> n >> m;
for (int i = 1; i <= n; ++i)
fin >> v[i];
for (int i = 1; i < n; ++i)
{
int x, y;
fin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
decompose();
for (int i = 1; i <= m; ++i)
{
int type, x, y;
fin >> type >> x >> y;
if (type == 0)
d[t[0][x]].set(1, 1, d[t[0][x]].count, t[1][x], v[x] = y);
else
fout << max_on_path(x, y) << '\n';
}
fin.close();
fout.close();
return 0;
}