#include <bits/stdc++.h>
#include <climits>
#define MAX_LOG 17
#define MAX_N 100005
using namespace std;
FILE *fin, *fout;
int N, M, global_idx = 1, global_path_idx = 1, Val, Pos, S, E;
vector<int> tree[MAX_N];
int aint[4 * MAX_N];
int dp[MAX_LOG][MAX_N];
int s[MAX_N], cost[MAX_N], depth[MAX_N], path_start[MAX_N];
struct node_info {
int idx, path_idx;
} info[MAX_N];
void update(int node, int start, int end) {
if(start == end) {
aint[node] = Val;
} else {
int mid = (start + end) / 2;
if(Pos <= mid)
update(2 * node, start, mid);
else
update(2 * node + 1, mid + 1, end);
aint[node] = max(aint[2 * node], aint[2 * node + 1]);
}
}
void query(int node, int start, int end) {
if(S <= start && end <= E) {
Val = max(Val, aint[node]);
} else {
int mid = (start + end) / 2;
if(S <= mid)
query(2 * node, start, mid);
if(E > mid)
query(2 * node + 1, mid + 1, end);
}
}
void precalc_hpd(int node) {
Pos = global_idx;
Val = cost[node];
info[node].idx = global_idx;
info[node].path_idx = global_path_idx;
update(1, 1, N);
int bestSon = 0;
for(auto &son: tree[node]) {
if(dp[0][node] != son && (bestSon == 0 || s[bestSon] < s[son]))
bestSon = son;
}
if(bestSon == 0) {
return;
}
global_idx++;
precalc_hpd(bestSon);
for(auto &son: tree[node]) {
if(son != dp[0][node] && son != bestSon) {
global_idx++;
path_start[++global_path_idx] = son;
precalc_hpd(son);
}
}
}
void hpd_update(int node, int value) {
Pos = info[node].idx;
Val = value;
update(1, 1, N);
}
int hpd_query(int father, int son) {
Val = INT_MIN;
while(info[father].path_idx != info[son].path_idx) {
S = info[path_start[info[son].path_idx]].idx;
E = info[son].idx;
query(1, 1, N);
son = dp[0][path_start[info[son].path_idx]];
}
S = info[father].idx;
E = info[son].idx;
query(1, 1, N);
return Val;
}
int precalc_lca(int node, int father, int d) {
dp[0][node] = father;
depth[node] = d;
s[node] = 1;
for(int i = 1; i < MAX_LOG; i++)
dp[i][node] = dp[i-1][dp[i - 1][node]];
for(auto &son: tree[node])
if(depth[son] == 0)
s[node] += precalc_lca(son, node, d + 1);
return s[node];
}
int lca(int x, int y) {
if(depth[x] > depth[y])
swap(x, y);
for(int i = MAX_LOG - 1; i >= 0; i--)
if(depth[dp[i][y]] >= depth[x])
y = dp[i][y];
if(x == y)
return x;
for (int i = MAX_LOG - 1; i >= 0; i--) {
if(dp[i][y] != dp[i][x]) {
y = dp[i][y];
x = dp[i][x];
}
}
return dp[0][x];
}
int main() {
fin = fopen("heavypath.in", "r");
fout = fopen("heavypath.out", "w");
fscanf(fin, "%d%d", &N, &M);
for(int i = 1; i<= N; i++)
fscanf(fin, "%d", &cost[i]);
for(int i = 1; i < N; i++) {
int x, y;
fscanf(fin, "%d%d", &x, &y);
tree[x].push_back(y);
tree[y].push_back(x);
}
precalc_lca(1, 1, 1);
path_start[1] = 1;
precalc_hpd(1);
for(int i = 0; i < M; i++) {
int type, x, y, z;
fscanf(fin, "%d%d%d", &type, &x, &y);
if(type == 0) {
hpd_update(x, y);
} else {
z = lca(x, y);
fprintf(fout, "%d\n", max(hpd_query(z, x), hpd_query(z, y)));
}
}
}