#include <bits/stdc++.h>
using namespace std;
const int N_MAX = 1e5;
const int INF = 2e9;
const int NONE = -1;
int DS[2 * N_MAX], input[N_MAX];
void build_up (int node, int left, int right) {
if (left == right)
DS[node] = input[left];
else {
int mid = left + (right - left) / 2;
build_up (node + 1, left, mid);
build_up (node + 2 * (mid - left + 1), mid + 1, right);
DS[node] = max (DS[node + 1], DS[node + 2 * (mid - left + 1)]);
}
}
void update (int node, int left, int right, int pos, int value) {
if (left == right)
DS[node] = value;
else {
int mid = left + (right - left) / 2;
if (pos <= mid)
update (node + 1, left, mid, pos, value);
else
update (node + 2 * (mid - left + 1), mid + 1, right, pos, value);
DS[node] = max (DS[node + 1], DS[node + 2 * (mid - left + 1)]);
}
}
int query (int node, int left, int right, int qleft, int qright) {
if (qleft <= left && right <= qright)
return DS[node];
int mid = left + (right - left) / 2;
int answer = -INF;
if (qleft <= mid)
answer = max (answer, query (node + 1, left, mid, qleft, qright));
if (mid + 1 <= qright)
answer = max (answer, query (node + 2 * (mid - left + 1), mid + 1, right, qleft, qright));
return answer;
}
int cost[N_MAX]; int n, q;
vector<int> tree[N_MAX];
int depth[N_MAX], sizof[N_MAX];
int start[N_MAX], posof[N_MAX];
int heavy_child[N_MAX], parent[N_MAX];
void dfs (int root, int p) {
depth[root] = depth[p] + 1;
parent[root] = p;
for (int node : tree[root])
if (node != p)
dfs (node, root);
sizof[root] = 1;
for (int node : tree[root])
if (node != p)
sizof[root] += sizof[node];
}
void decompose (int root, int p, int curr_start) {
start[root] = curr_start;
int winner = NONE, maxSize = 0;
for (int node : tree[root])
if (node != p)
if (maxSize < sizof[node])
maxSize = sizof[node], winner = node;
heavy_child[root] = winner;
for (int node : tree[root])
if (node != p) {
if (node == winner)
decompose (node, root, curr_start);
else
decompose (node, root, node);
}
}
void construct_chain () {
for (int node = 0; node < n; node ++) {
posof[node] = NONE;
heavy_child[node] = NONE;
}
decompose (0, NONE, 0);
int curr_pos = 0;
for (int node = 0; node < n; node ++) {
if (start[node] == node) {
int aux = node;
do {
posof[aux] = curr_pos ++;
aux = heavy_child[aux];
}
while (aux != NONE);
}
}
}
void HLD_update (int node, int new_value) {
input[posof[node]] = new_value;
update (0, 0, n - 1, posof[node], new_value);
}
int HLD_query (int u, int v) {
int answer = -INF;
while (start[u] != start[v]) {
if (depth[start[u]] < depth[start[v]])
swap (u, v);
answer = max (answer, query (0, 0, n - 1, posof[start[u]], posof[u]));
u = parent[start[u]];
}
if (posof[u] > posof[v])
swap (u, v);
answer = max (answer, query (0, 0, n - 1, posof[u], posof[v]));
return answer;
}
int main()
{
ifstream in ("heavypath.in");
ofstream out ("heavypath.out");
in >> n >> q;
for (int node = 0; node < n; node ++)
in >> cost[node];
for (int i = 0; i < n - 1; i ++) {
int u, v; in >> u >> v; u --, v --;
tree[u].push_back (v);
tree[v].push_back (u);
}
dfs (0, NONE);
decompose (0, NONE, 0);
construct_chain ();
for (int node = 0; node < n; node ++)
input[posof[node]] = cost[node];
build_up (0, 0, n - 1);
for (int i = 0; i < q; i ++) {
int t; in >> t;
if (t == 0) {
int node, new_value; in >> node >> new_value; node --;
HLD_update (node, new_value);
}
else {
int u, v; in >> u >> v; u --, v --;
out << HLD_query (u, v) << "\n";
}
}
return 0;
}