#include <vector>
#include <fstream>
#include <cstdio>
#include <queue>
#include <climits>
#include <iostream>
#define pb push_back
using namespace std;
class Node {
public:
int value, heavy, pos, path, level;
Node() {
heavy = 1;
level = 1;
}
};
int N, M, nrPaths, whichPath = 1;
vector <vector <int> > graph, decPath, segmentTree;
vector <Node> nodes;
void dfs_sum(int iam, int from = 0);
void dfs_paths(int iam, int from, int path);
void make_trees();
void insert_segment_tree(vector <int> &tree, int node, int alpha, int omega, int locus, int value);
int query_segment_tree(vector <int> &tree, int node, int alpha, int omega, int queryAlpha, int queryOmega);
int main() {
#ifdef INFOARENA
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
#else
freopen("input", "r", stdin);
#endif
int i, from, to, t, x, y, rez, path;
basic_ios<char>::sync_with_stdio(false);
scanf("%d %d", &N, &M);
graph.resize(N + 1);
nodes.resize(N + 1);
for (i = 1; i <= N; ++i) {
// scanf("%d", &nodes[i].value);
cin >> nodes[i].value;
}
nodes[0].level = 0;
for (i = 1; i < N; ++i) {
// scanf("%d %d", &from, &to);
cin >> from >> to;
graph[from].push_back(to);
graph[to].push_back(from);
}
dfs_sum(1);
decPath.resize(nrPaths + 1);
segmentTree.resize(nrPaths + 1);
dfs_paths(1, 0, whichPath);
make_trees();
for (i = 0; i < M; ++i) {
// scanf("%d %d %d", &t, &x, &y);
cin >> t >> x >> y;
if (t == 0) {
path = nodes[x].path;
insert_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, nodes[x].pos, y);
}
else {
rez = 0;
while (nodes[x].path != nodes[y].path) {
if (nodes[decPath[nodes[x].path][0]].level > nodes[decPath[nodes[y].path][0]].level) {
path = nodes[x].path;
rez = max(rez, query_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, 1, nodes[x].pos));
x = decPath[path][0];
}
else {
path = nodes[y].path;
rez = max(rez, query_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, 1, nodes[y].pos));
y = decPath[path][0];
}
}
path = nodes[x].path;
from = min(nodes[x].pos, nodes[y].pos);
to = max(nodes[x].pos, nodes[y].pos);
rez = max(rez, query_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, from, to));
printf("%d\n", rez);
}
}
return 0;
}
void dfs_sum(int iam, int from) {
if (graph[iam].size() == 1 && from > 0) {
++nrPaths;
return;
}
for (auto to: graph[iam]) {
if (to != from) {
dfs_sum(to, iam);
nodes[iam].heavy += nodes[to].heavy;
}
}
}
void dfs_paths(int iam, int from, int path) {
if (decPath[path].size() == 0) {
decPath[path].push_back(from);
}
decPath[path].push_back(iam);
nodes[iam].level = nodes[from].level + 1;
nodes[iam].path = path;
nodes[iam].pos = (int) decPath[path].size() - 1;
if (graph[iam].size() > 0) {
int _pos = -1, _max = 0;
for (auto to: graph[iam]) {
if (to != from) {
if (nodes[to].heavy > _max) {
_max = nodes[to].heavy;
_pos = to;
}
}
}
for (auto to: graph[iam]) {
if (to != from && to != _pos) {
++whichPath;
dfs_paths(to, iam, whichPath);
}
}
if (_pos > 0) {
dfs_paths(_pos, iam, path);
}
}
}
void make_trees() {
int i, sz, j;
for (i = 1; i <= nrPaths; ++i) {
sz = (int) decPath[i].size();
segmentTree[i].resize(sz * 4);
for (j = 1; j < sz; ++j) {
insert_segment_tree(segmentTree[i], 1, 1, sz - 1, j, nodes[decPath[i][j]].value);
}
}
}
int query_segment_tree(vector <int> &tree, int node, int alpha, int omega, int queryAlpha, int queryOmega) {
if (queryAlpha <= alpha && omega <= queryOmega) {
return tree[node];
}
int centro = (alpha + omega) / 2, rez1 = 0, rez2 = 0;
if (queryAlpha <= centro) {
rez1 = query_segment_tree(tree, node * 2, alpha, centro, queryAlpha, queryOmega);
}
if (centro < queryOmega) {
rez2 = query_segment_tree(tree, node * 2 + 1, centro + 1, omega, queryAlpha, queryOmega);
}
return max(rez1, rez2);
}
void insert_segment_tree(vector <int> &tree, int node, int alpha, int omega, int locus, int value) {
if (alpha == omega && omega == locus) {
tree[node] = value;
return;
}
int centro = (alpha + omega) / 2;
if (locus <= centro) {
insert_segment_tree(tree, node * 2, alpha, centro, locus, value);
}
else {
insert_segment_tree(tree, node * 2 + 1, centro + 1, omega, locus, value);
}
tree[node] = max(tree[node * 2], tree[node * 2 + 1]);
}