#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vll;
int SZ;
vector<int> st;
void build() {
for(int x = SZ-1; x; --x) {
st[x] = max(st[2*x], st[2*x+1]);
}
}
void set_val(int x, int val) {
for(st[x += SZ] = val; x; x /= 2) {
st[x/2] = max(st[x], st[x^1]);
}
}
int query(int l, int r) {
int res = 0;
for(l += SZ, r+= SZ; l < r; l /= 2, r /= 2) {
if (l&1) { res = max(res, st[l]); l++; }
if (r&1) { --r; res = max(res, st[r]); }
}
return res;
}
int main(void) {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
freopen("heavypath.in", "r", stdin);
freopen("heavypath.out", "w", stdout);
int N, M;
cin >> N >> M;
vector<int> A(N);
for(auto &a: A) { cin >> a; }
SZ= 1; while(SZ < N) SZ *= 2;
st.resize(2*SZ, 0);
int edge_cnt = 0;
vector<int> nxt(2*N), head(N), ende(2*N);
auto add_edge = [&](int u, int v){
edge_cnt++;
nxt[edge_cnt] = head[u];
head[u] = edge_cnt;
ende[edge_cnt] = v;
};
for(int i = 1; i < N; i++) {
int u, v;
cin >> u >> v;
--u, --v;
add_edge(u, v);
add_edge(v, u);
}
vector<int> depth(N), par(N, -1), heavy(N,-1);
auto dfs = [&](auto self, int nod, int src)->int {
int sz = 1, max_subtree = 0;
for(int e = head[nod]; e; e = nxt[e]) {
int nbr = ende[e];
if (nbr == src) continue;
par[nbr] = nod;
depth[nbr] = depth[nod] + 1;
int subtree_sz = self(self, nbr, nod);
if (subtree_sz > max_subtree) {
max_subtree = subtree_sz;
heavy[nod] = nbr;
}
sz += subtree_sz;
}
return sz;
};
dfs(dfs, 0, -1);
vector<int> treePos(N), root(N);
for(int nod = 0, currentPos = 0; nod < N; ++nod) {
if (par[nod] == -1 || heavy[par[nod]] != nod) { // start new heavy path at nod;
for(int ch = nod; ch != -1; ch = heavy[ch]) {
root[ch] = nod;
treePos[ch] = currentPos++;
}
}
}
auto dbg = [&]() {
cout << std::left << setw(12) << "depth:";
for(int i = 0; i < N; i++) { cout << depth[i] << " "; } cout << endl;
cout << setw(12) << "parent:";
for(int i = 0; i < N; i++) { cout << par[i] + 1 << " "; } cout << endl;
cout << setw(12) << "heavy:";
for(int i = 0; i < N; i++) { cout << heavy[i] + 1 << " "; } cout << endl;
cout << setw(12) << "treePos:";
for(int i = 0; i < N; i++) { cout << treePos[i] << " "; } cout << endl;
cout << setw(12) << "root:";
for(int i = 0; i < N; i++) { cout << root[i] + 1 << " "; } cout << endl;
};
// dbg();
for(int i = 0; i < N; ++i) {
st[treePos[i] + SZ] = A[i];
}
build();
auto dbg2 = [&](){
cout << string(60,'-') << endl;
cout << std::left << setw(12) << "segtree:";
for(int i = 1; i < (int)st.size(); i++) { cout << st[i] << ' '; } cout << endl;
};
// dbg2();
for(int mm = 1; mm <= M; mm++) {
int q, a,b;
cin >> q >> a >> b;
if (q == 0) {
--a;
set_val(a, b);
// dbg2();
} else {
--a, --b;
int res = 0;
for(; root[a] != root[b]; b = par[root[b]]) {
if (depth[root[a]] > depth[root[b]]) swap(a,b);
res = max(res, query(treePos[root[b]], treePos[b]+1));
}
if (depth[a] > depth[b]) swap(a,b);
res = max(res, query(treePos[a], treePos[b]+1));
// cout << setw(10) << "ANS:";
cout << res << "\n";
}
}
return 0;
}