#ifndef LOCAL
#pragma GCC optimize("O3")
#pragma GCC target("avx2")
#endif
#ifdef LOCAL
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
#define pb push_back
#define pii pair<int, int>
using ll = long long;
using ci = const int;
using cll = const long long;
using namespace std;
/*******************************/
// INPUT / OUTPUT
#ifndef LOCAL
ifstream in("heavypath.in");
ofstream out("heavypath.out");
#define cin in
#define cout out
#endif
/*******************************/
/// GLOBAL DECLARATIONS
int N, Q;
struct Node
{
int val, w, h, par, idx, care;
vector <int> adj;
};
struct ArbInt
{
inline int next_power_of_two(int n)
{
int p = 1;
while (p <= n)
p <<= 1;
return p;
}
int offset;
vector <int> data;
ArbInt(int n)
{
offset = next_power_of_two(n);
data.resize(2 * offset);
}
inline void _update(int node, int st, int dr, int pos, int val)
{
if (st == dr)
{
data[node] = val;
return;
}
int mid = (st + dr) / 2;
if (pos <= mid)
_update(2 * node, st, mid, pos, val);
else
_update(2 * node + 1, mid + 1, dr, pos, val);
data[node] = max(data[2 * node], data[2 * node + 1]);
return;
}
inline void update(int pos, int val)
{
_update(1, 0, offset - 1, pos, val);
}
inline int _query(int node, int st, int dr, int q_st, int q_dr)
{
if (dr < q_st || q_dr < st) return 0;
if (q_st <= st && dr <= q_dr)
return data[node];
int mid = (st + dr) / 2;
int rasp_st = _query(2 * node, st, mid, q_st, q_dr);
int rasp_dr = _query(2 * node + 1, mid + 1, dr, q_st, q_dr);
return max(rasp_st, rasp_dr);
}
inline int query(int q_st, int q_dr)
{
return _query(1, 0, offset - 1, q_st, q_dr);
}
};
struct HeavyPathDecomp
{
vector <int> reps;
vector <Node> v;
ArbInt arb = ArbInt(5);
HeavyPathDecomp(int n)
{
v.resize(n);
arb = ArbInt(n);
}
inline void dfs(int node, int par, int h)
{
v[node].h = h;
v[node].par = par;
v[node].w = 1;
for (auto u: v[node].adj)
{
if (u == par) continue;
dfs(u, node, h + 1);
v[node].w += v[u].w;
}
}
inline void imparte(int node, int par, int &timp, int &lant)
{
if (reps.size() == lant)
reps.push_back(node);
v[node].idx = timp ++;
v[node].care = lant;
int best_w = -1, best = -1;
for (auto u: v[node].adj)
{
if (u == par) continue;
if (best_w < v[u].w)
{
best_w = v[u].w;
best = u;
}
}
if (best != -1)
{
imparte(best, node, timp, lant);
for (auto u: v[node].adj)
{
if (u == par || u == best) continue;
imparte(u, node, timp, ++ lant);
}
}
}
inline void init()
{
dfs(0, -1, 0);
int timp = 0, lant = 0;
imparte(0, -1, timp, lant);
int rep;
for (int node = 0 ; node < v.size() ; ++ node)
{
rep = reps[v[node].care];
arb.update(v[rep].idx + v[node].h - v[rep].h, v[node].val);
}
}
inline void update(int node, int val)
{
int rep = reps[v[node].care];
v[node].val = val;
arb.update(v[rep].idx + v[node].h - v[rep].h, v[node].val);
}
inline int query(int a, int b)
{
int rep_a = reps[v[a].care];
int rep_b = reps[v[b].care];
int ans = -1;
while (rep_a != rep_b)
{
if (v[rep_a].h < v[rep_b].h)
{
swap(a, b);
swap(rep_a, rep_b);
}
ans = max(ans, arb.query(v[rep_a].idx, v[rep_a].idx + v[a].h - v[rep_a].h));
a = v[rep_a].par;
rep_a = reps[v[a].care];
}
if (v[a].h > v[b].h)
{
swap(a, b);
swap(rep_a, rep_b);
}
ans = max(ans, arb.query(v[rep_a].idx + v[a].h - v[rep_a].h, v[rep_b].idx + v[b].h - v[rep_b].h));
return ans;
}
};
/*******************************/
/// FUNCTIONS
void ReadInput();
void Solution();
void Output();
/*******************************/
///-------------------------------------
inline void ReadInput()
{
cin >> N >> Q;
}
///-------------------------------------
inline void Solution()
{
HeavyPathDecomp hvy = HeavyPathDecomp(N);
for (int i = 0 ; i < N ; ++ i)
cin >> hvy.v[i].val;
int a, b;
for (int i = 1 ; i < N ; ++ i)
{
cin >> a >> b;
a --; b --;
hvy.v[a].adj.push_back(b);
hvy.v[b].adj.push_back(a);
}
hvy.init();
int tip;
while (Q --)
{
cin >> tip >> a >> b;
if (tip == 0)
{
a --;
hvy.update(a, b);
}
else
{
a --; b --;
cout << hvy.query(a, b) << "\n";
}
}
}
///-------------------------------------
inline void Output()
{
}
///-------------------------------------
int main()
{
#ifndef LOCAL
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
#endif
ReadInput();
Solution();
Output();
return 0;
}