#include <stdio.h>
#include <vector>
#define SZ(x) ((int)(x.size()))
#define nmax 100010
using namespace std;
int n, m, x, y;
int totalChainsNumber;
int v[nmax], sz[nmax], parent[nmax], parentChain[nmax], numberOfChain[nmax], value[nmax];
vector <int> graph[nmax];
vector <int> chainNodes[nmax];
vector <int> arb[nmax];
int my_log2(int x)
{
int nr = 0;
while (x > 0) { x /= 2; nr++; }
return nr + 1;
}
void my_swap(int &a, int &b)
{
int aux = a; a = b; b = aux;
}
void dfs(int node, int p)
{
sz[node] = 1;
for (int i = 0; i < SZ(graph[node]); i++)
if (graph[node][i] != p) {
dfs(graph[node][i], node);
parent[graph[node][i]] = node;
sz[node] += sz[graph[node][i]];
}
}
void hld(int node, int p, int chain_number)
{
chainNodes[chain_number].push_back(node);
int mx = -1, index_max_child = -1;
for (int i = 0; i < SZ(graph[node]); i++)
if (sz[graph[node][i]] > mx && graph[node][i] != p) {
mx = sz[graph[node][i]];
index_max_child = graph[node][i];
}
// not leaf
if (mx != -1) {
parentChain[index_max_child] = parentChain[node];
numberOfChain[index_max_child] = chain_number;
hld(index_max_child, node, chain_number);
}
// for other nodes than max start a new chain
for (int i = 0; i < SZ(graph[node]); i++)
if (graph[node][i] != index_max_child && graph[node][i] != p) {
totalChainsNumber++;
parentChain[graph[node][i]] = node;
numberOfChain[graph[node][i]] = totalChainsNumber;
hld(graph[node][i], node, totalChainsNumber);
}
}
void build(int idx, int node, int l, int r)
{
if (l == r) {
arb[idx][node] = v[chainNodes[idx][l - 1]];
return;
}
int m = (l + r) / 2;
build(idx, node * 2, l, m);
build(idx, node * 2 + 1, m + 1, r);
arb[idx][node] = max(arb[idx][node * 2], arb[idx][node * 2 + 1]);
}
void update(int idx, int node, int l, int r, int pos, int val)
{
if (l == r) {
arb[idx][node] = val;
return;
}
int m = (l + r) / 2;
if (pos <= m) update(idx, node * 2, l, m, pos, val); else
update(idx, node * 2 + 1, m + 1, r, pos, val);
arb[idx][node] = max(arb[idx][node * 2], arb[idx][node * 2 + 1]);
}
int query(int idx, int node, int l, int r, int pl, int pr)
{
if (l >= pl && r <= pr) return arb[idx][node];
int answer = -1;
int m = (l + r) / 2;
if (pl <= m) answer = max(answer, query(idx, node * 2, l, m, pl, pr));
if (pr > m) answer = max(answer, query(idx, node * 2 + 1, m + 1, r, pl, pr));
return answer;
}
void build_arb(int idx)
{
int size = SZ(chainNodes[idx]);
arb[idx].reserve(size * my_log2(size));
build(idx, 1, 1, size);
for (int i = 0; i < SZ(chainNodes[idx]); i++) value[chainNodes[idx][i]] = i + 1;
}
int _query(int l, int r)
{
int answer = -1;
while (numberOfChain[l] != numberOfChain[r]) {
if (numberOfChain[l] > numberOfChain[r]) {
int x = numberOfChain[l];
answer = max(answer, query(x, 1, 1, SZ(chainNodes[x]), 1, value[l]));
l = parentChain[l];
} else {
int x = numberOfChain[r];
answer = max(answer, query(x, 1, 1, SZ(chainNodes[x]), 1, value[r]));
r = parentChain[r];
}
}
int x = numberOfChain[l];
if (value[l] > value[r]) my_swap(l, r);
answer = max(answer, query(x, 1, 1, SZ(chainNodes[x]), value[l], value[r]));
return answer;
}
int main()
{
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
for (int i = 1; i < n; i++) {
scanf("%d %d", &x, &y);
graph[x].push_back(y);
graph[y].push_back(x);
}
parentChain[1] = 0;
numberOfChain[1] = 1;
totalChainsNumber = 1;
dfs(1, 0);
hld(1, 0, 1);
for (int i = 1; i <= totalChainsNumber; i++) build_arb(i);
for (int i = 1; i <= m; i++) {
int t, x, y;
scanf("%d %d %d", &t, &x, &y);
if (t == 0) update(numberOfChain[x], 1, 1, SZ(chainNodes[numberOfChain[x]]), value[x], y); else
printf("%d\n", _query(x, y));
}
return 0;
}