#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <stack>
#include <cassert>
#include <map>
#include <numeric>
#include <cstring>
#include <set>
#include <ctime>
#include <queue>
#include <cmath>
#include <iomanip>
#include <iterator>
#include <bitset>
#include <unordered_map>
#include <complex>
#include <unordered_set>
#include <chrono>
#include <random>
#include <array>
#include <functional>
#include <random>
///6:21
using namespace std;
const int maxN = 100009;
int N, M, nr, aint[4 * maxN], q[maxN], pos[maxN], sz[maxN], t[maxN], fst[maxN], a[maxN], lev[maxN];
vector<int> v[maxN], sons[maxN];
void dfsSz(int nod) {
int biggestSon = -1;
sz[nod] = 1;
for (auto it : v[nod])
if (it != t[nod]) {
t[it] = nod, lev[it] = lev[nod] + 1, dfsSz (it);
if (biggestSon == -1 || sz[it] > sz[biggestSon])
biggestSon = it;
sz[nod] += sz[it];
}
if (biggestSon != -1)
sons[nod].push_back(biggestSon);
for (auto it : v[nod])
if (it != t[nod] && it != biggestSon)
sons[nod].push_back(it);
}
void dfs(int nod) {
pos[nod] = ++nr, q[nr] = nod;
for (auto it : sons[nod]) {
fst[it] = (it == sons[nod][0]) ? fst[nod] : it;
dfs(it);
}
}
void build(int nod, int st, int dr) {
if (st == dr) {
aint[nod] = a[q[st]];
return ;
}
int mid = (st + dr) >> 1, f1 = nod << 1, f2 = f1 | 1;
build(f1, st, mid);
build(f2, mid + 1, dr);
aint[nod] = max(aint[f1], aint[f2]);
}
void update(int nod, int st, int dr, int pos) {
if (st == dr) {
aint[nod] = a[q[st]];
return ;
}
int mid = (st + dr) >> 1, f1 = nod << 1, f2 = f1 | 1;
if (pos <= mid) update(f1, st, mid, pos);
else update(f2, mid + 1, dr, pos);
aint[nod] = max(aint[f1], aint[f2]);
}
int ansQ = 0;
void query(int nod, int st, int dr, int x, int y) {
/*if (nod == 1)
printf("queried [%d, %d]", x, y);*/
if (x <= st && dr <= y) {
if (x == st) ansQ = aint[nod];
else ansQ = max(ansQ, aint[nod]);
return ;
}
int mid = (st + dr) >> 1, f1 = nod << 1, f2 = f1 | 1;
if (x <= mid) query(f1, st, mid, x, y);
if (mid < y) query(f2, mid + 1, dr, x, y);
//if (nod == 1) printf("->%d ", ansQ);
}
int query(int x, int y) {
//printf("recursed to [%d, %d]", x, y);
if (fst[x] == fst[y]) {
x = pos[x], y = pos[y];
if (x > y) swap(x, y);
query(1, 1, N, x, y);
return ansQ;
}
if (lev[fst[x]] > lev[fst[y]])
swap(x, y);
query(1, 1, N, pos[fst[y]], pos[y]);
int ans = ansQ;
ans = max(ans, query(x, t[fst[y]]));
return ans;
}
int main() {
//freopen("../input", "r", stdin);
//freopen("../output", "w", stdout);
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
scanf("%d %d", &N, &M);
for (int i=1; i<=N; i++)
scanf("%d", &a[i]);
for (int i=1; i<N; i++) {
int x, y;
scanf("%d %d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
t[1] = -1, dfsSz(1);
fst[1] = 1, dfs(1), assert(nr == N);
build(1, 1, N);
/*for (int i=1; i<=N; i++) {
if (fst[q[i]] == q[i])
printf("|");
printf("%d ", q[i]);
}
printf("\n");*/
while (M --) {
int type, x, y;
scanf("%d %d %d", &type, &x, &y);
if (type == 0) {
a[x] = y;
update(1, 1, N, pos[x]);
continue;
}
printf("%d\n", query(x, y));
}
return 0;
}
/*const int seed = time (0);
mt19937 gen (seed);
long long getRand(long long a, long long b) {return uniform_int_distribution < long long > (a, b) (gen);}*/