#include <bits/stdc++.h>
using namespace std;
const int NMAX = 100010;
int N, M, currPath;
int values[NMAX];
int size[NMAX], where[NMAX], pathFather[NMAX], level[NMAX], pathPos[NMAX];
vector<int> T[NMAX], path[NMAX];
struct Node {
int value, size, maxVal, priority;
Node *left, *right;
Node(int value, int size, int maxVal, int priority, Node *left, Node *right):
value(value),
size(size),
maxVal(maxVal),
priority(priority),
left(left),
right(right) {
}
} *nil, *root[NMAX];
void heavyDFS(int node, int father, int currLevel) {
size[node] = 1;
level[node] = currLevel;
if (T[node].size() == 1 && father != -1) {
where[node] = currPath;
path[currPath].push_back(node);
pathPos[node] = path[currPath++].size() - 1;
return;
}
int maxSubtree = -1;
for (int i: T[node]) {
if (i == father)
continue;
heavyDFS(i, node, currLevel + 1);
size[node] += size[i];
if (maxSubtree == -1 || size[maxSubtree] < size[i])
maxSubtree = i;
}
path[where[maxSubtree]].push_back(node);
pathPos[node] = path[where[maxSubtree]].size() - 1;
where[node] = where[maxSubtree];
for (int i: T[node]) {
if (i == maxSubtree || i == father)
continue;
pathFather[where[i]] = node;
}
}
void updateNode(Node *curr) {
if (curr == nil)
return;
curr->maxVal = max(curr->value, max(curr->left->maxVal, curr->right->maxVal));
curr->size = curr->left->size + curr->right->size + 1;
}
Node *joinTreaps(Node *left, Node *right) {
if (left == nil)
return right;
if (right == nil)
return left;
if (left->priority > right->priority) {
Node *temp = joinTreaps(left->right, right);
left->right = temp;
updateNode(left);
return left;
}
Node *temp = joinTreaps(left, right->left);
right->left = temp;
updateNode(right);
return right;
}
pair<Node *, Node *> splitTreaps(Node *node, int pos) {
if (node == nil)
return {nil, nil};
if (pos == node->left->size + 1) {
Node *temp = node->right;
node->right = nil;
updateNode(node);
return {node, temp};
}
if (pos < node->left->size + 1) {
auto split = splitTreaps(node->left, pos);
node->left = split.second;
updateNode(node);
return {split.first, node};
}
auto split = splitTreaps(node->right, pos - node->left->size - 1);
node->right = split.first;
updateNode(node);
return {node, split.second};
}
int maxValue(Node *&node, int x, int y) {
if (x > y)
swap(x, y);
++x, ++y;
auto split1 = splitTreaps(node, x - 1);
auto split2 = splitTreaps(split1.second, y - x + 1);
int answer = split2.first->maxVal;
node = joinTreaps(split1.first, split2.first);
node = joinTreaps(node, split2.second);
return answer;
}
void updateValue(Node *node, int value, int pos) {
if (node == nil)
return;
if (pos == node->left->size + 1) {
node->value = value;
updateNode(node);
return;
}
if (pos < node->left->size + 1)
updateValue(node->left, value, pos);
else
updateValue(node->right, value, pos - 1 - node->left->size);
updateNode(node);
}
int main() {
assert(freopen("heavypath.in", "r", stdin));
assert(freopen("heavypath.out", "w", stdout));
int i;
cin >> N >> M;
for (i = 1; i <= N; ++i)
cin >> values[i];
for (i = 0; i < N - 1; ++i) {
int x, y;
cin >> x >> y;
T[x].push_back(y);
T[y].push_back(x);
}
heavyDFS(1, -1, 0);
srand(time(0));
nil = new Node(numeric_limits<int>::min(), 0, numeric_limits<int>::min(), -1, nullptr, nullptr);
nil->left = nil->right = nil;
for (i = 0; i < currPath; ++i) {
root[i] = nil;
for (int j: path[i]) {
Node *temp = new Node(values[j], 1, values[j], rand(), nil, nil);
root[i] = joinTreaps(root[i], temp);
}
}
while (M--) {
int opType, x, y;
cin >> opType >> x >> y;
if (opType == 0) {
updateValue(root[where[x]], y, pathPos[x] + 1);
} else {
int answer = numeric_limits<int>::min();
while (where[x] != where[y]) {
if (level[pathFather[where[x]]] < level[pathFather[where[y]]])
swap(x, y);
answer = max(answer, maxValue(root[where[x]], pathPos[x], path[where[x]].size() - 1));
x = pathFather[where[x]];
}
answer = max(answer, maxValue(root[where[x]], pathPos[x], pathPos[y]));
cout << answer << '\n';
}
}
return 0;
}