#include <fstream>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <map>
#include <set>
#include <stack>
#include <unordered_map>
#include <vector>
#include <string>
#define ll long long
using namespace std;
ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
const int NMAX = 1e5;
int n, m, ind, paths = 1;
int values[NMAX + 1];
int sub_tree_size[NMAX + 1];
int heavy[NMAX + 1];
int parent[NMAX + 1];
int depth[NMAX + 1];
int pos[NMAX + 1];
int head[NMAX + 1];
int path[NMAX + 1];
vector<int> G[NMAX + 1];
int aint[4 * NMAX + 1];
void Build(int node, int left, int right) {
if (left == right) {
aint[node] = path[left];
return;
}
int mid = (left + right) / 2;
Build(node * 2, left, mid);
Build(node * 2 + 1, mid + 1, right);
aint[node] = max(aint[node * 2], aint[node * 2 + 1]);
}
void Update(int node, int left, int right, int pos, int value) {
if (left == right) {
aint[node] = value;
return;
}
int mid = (left + right) / 2;
if (pos <= mid) {
Update(node * 2, left, mid, pos, value);
}
else {
Update(node * 2 + 1, mid + 1, right, pos, value);
}
aint[node] = max(aint[node * 2], aint[node * 2 + 1]);
}
int Query(int node, int left, int right, int Qleft, int Qright) {
if (left >= Qleft && right <= Qright) {
return aint[node];
}
int mid = (left + right) / 2;
if (mid >= Qright) {
return Query(node * 2, left, mid, Qleft, Qright);
}
if (mid + 1 <= Qleft) {
return Query(node * 2 + 1, mid + 1, right, Qleft, Qright);
}
int left_node = Query(node * 2, left, mid, Qleft, Qright);
int right_node = Query(node * 2 + 1, mid + 1, right, Qleft, Qright);
return max(left_node, right_node);
}
void DFS(int node = 1, int dad = 0) {
parent[node] = dad;
depth[node] = depth[dad] + 1;
sub_tree_size[node] = 1;
for (int next_node : G[node]) {
if (next_node != dad) {
DFS(next_node, node);
sub_tree_size[node] += sub_tree_size[next_node];
if (sub_tree_size[next_node] > sub_tree_size[heavy[node]]) {
heavy[node] = next_node;
}
}
}
}
void DFSHeavy(int node = 1, int curent_head = 1, int dad = 0) {
head[node] = curent_head;
path[++ind] = values[node];
pos[node] = ind;
if (heavy[node]) {
DFSHeavy(heavy[node], curent_head, node);
}
for (int next_node : G[node]) {
if (next_node != dad && next_node != heavy[node]) {
paths++;
DFSHeavy(next_node, next_node, node);
}
}
}
int Query(int x, int y) {
int answer = 0;
while (head[x] != head[y]) {
if (depth[head[x]] < depth[head[y]]) {
swap(x, y); /// In x am ala mai jos
}
answer = max(answer, Query(1, 1, ind, pos[head[x]], pos[x]));
x = parent[head[x]];
}
if (depth[x] < depth[y]) {
swap(x, y);
}
answer = max(answer, Query(1, 1, ind, pos[y], pos[x]));
return answer;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> values[i];
}
for (int i = 1; i <= n - 1; i++) {
int a, b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
DFS();
DFSHeavy();
Build(1, 1, ind);
while (m--) {
int type, x, y;
cin >> type >> x >> y;
if (type == 0) {
Update(1, 1, ind, x, y);
}
else {
cout << Query(x, y) << '\n';
}
}
return 0;
}