#include <cstdio>
#include <vector>
#include <algorithm>
const int MAX_N = 100000;
class SegmentTree {
public:
int value;
int leftIndex;
int rightIndex;
SegmentTree* left;
SegmentTree* right;
void update(int pos, int newValue) {
int size = (int)(rightIndex - leftIndex);
if (size == 1) {
value = newValue;
return;
}
if (pos < leftIndex + size / 2)
left->update(pos, newValue);
else
right->update(pos, newValue);
value = std::max(left->value, right->value);
}
int query(int leftQ, int rightQ) {
int size = (int)(rightIndex - leftIndex);
if (leftQ <= leftIndex && rightIndex <= rightQ)
return value;
int tempAns = 0;
if (leftQ < leftIndex + size / 2)
tempAns = std::max(tempAns, left->query(leftQ, rightQ));
if (rightQ - 1 >= leftIndex + size / 2)
tempAns = std::max(tempAns, right->query(leftQ, rightQ));
return tempAns;
}
};
struct Path {
std::vector<int> nodes;
SegmentTree* root;
Path() {
root = NULL;
}
};
struct Range {
int high;
int low;
// high <= low
Range() {
high = MAX_N;
low = 0;
}
Range(int _high, int _low) {
high = _high;
low = _low;
}
};
int a[1 + MAX_N];
std::vector<int> tree[1 + MAX_N];
Path paths[1 + MAX_N];
int subTree[1 + MAX_N];
int level[1 + MAX_N];
int path[1 + MAX_N];
int posInPath[1 + MAX_N];
Range range[1 + MAX_N];
int dad[1 + MAX_N];
int leaves;
SegmentTree* buildSegmentTree(std::vector<int>::iterator begin, std::vector<int>::iterator end, int leftIndex, int rightIndex) {
int size = (int)(end - begin);
if (size == 1)
return new SegmentTree {a[*begin], leftIndex, rightIndex, NULL, NULL};
SegmentTree* left = buildSegmentTree(begin, begin + size / 2, leftIndex, leftIndex + size / 2);
SegmentTree* right = buildSegmentTree(begin + size / 2, end, leftIndex + size / 2, rightIndex);
int value = std::max(left->value, right->value);
return new SegmentTree {value, leftIndex, rightIndex, left, right};
}
void dfs(int v, int last = 0) {
subTree[v] = 1;
dad[v] = last;
level[v] = level[last] + 1;
int biggestSon = 0;
for (auto u : tree[v]) {
if (u != last) {
dfs(u, v);
subTree[v] += subTree[u];
if (subTree[biggestSon] < subTree[u])
biggestSon = u;
}
}
if (biggestSon == 0)
path[v] = ++leaves;
else
path[v] = path[biggestSon];
paths[path[v]].nodes.push_back(v);
posInPath[v] = (int)paths[path[v]].nodes.size();
range[path[v]] = Range(std::min(range[path[v]].high, level[v]), std::max(range[path[v]].low, level[v]));
}
int main() {
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n - 1; i++) {
int u, v;
scanf("%d%d", &u, &v);
tree[u].push_back(v);
tree[v].push_back(u);
}
dfs(1);
for (int i = 1; i <= leaves; i++)
paths[i].root = buildSegmentTree(paths[i].nodes.begin(), paths[i].nodes.end(), 1, (int)paths[i].nodes.size() + 1);
for (int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if (t == 0) {
paths[path[x]].root->update(posInPath[x], y);
} else {
int ans = 0;
while (x != y) {
if (level[x] < level[y])
std::swap(x, y);
if (level[x] > level[y]) { // x e mai jos
while (range[path[x]].high > level[y]) {
int size = (int)paths[path[x]].nodes.size();
ans = std::max(ans, paths[path[x]].root->query(posInPath[x], size + 1));
x = dad[paths[path[x]].nodes[size - 1]];
}
ans = std::max(ans, paths[path[x]].root->query(posInPath[x], posInPath[x] + level[x] - level[y] + 1));
x = paths[path[x]].nodes[posInPath[x] - 1 + level[x] - level[y]];
} else {
int sizeX = (int)paths[path[x]].nodes.size();
int sizeY = (int)paths[path[y]].nodes.size();
if (level[dad[paths[path[x]].nodes[sizeX - 1]]] > level[dad[paths[path[y]].nodes[sizeY - 1]]]) {
ans = std::max(ans, paths[path[x]].root->query(posInPath[x], sizeX + 1));
x = dad[paths[path[x]].nodes[sizeX - 1]];
} else {
ans = std::max(ans, paths[path[y]].root->query(posInPath[y], sizeY + 1));
y = dad[paths[path[y]].nodes[sizeY - 1]];
}
}
}
printf("%d\n", ans);
}
}
return 0;
}