#include<fstream>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
ifstream in("heavypath.in");
ofstream out("heavypath.out");
int arb[100000 * 5 + 30];
class segment_tree
{
vector<int> arb;
void create(int x,int y,int k, const vector<int> &vec)
{
if (x == y)
{
arb[k] = vec[x-1];
return;
}
int mid = (x + y) / 2;
create(x, mid, k * 2, vec);
create(mid + 1, y, k * 2 + 1, vec);
arb[k] = max(arb[k * 2], arb[k * 2 + 1]);
}
public:
void create(const vector<int> &vec)
{
arb.resize(vec.size() * 5);
create(1, vec.size(), 1, vec);
}
void update(int el, int x, int y, int val, int k)
{
int mid = (x + y) / 2;
if (x == y && el == y)
{
arb[k] = val;
return;
}
else if (el <= mid)
update(el, x, mid, val, k * 2);
else
update(el, mid + 1, y, val, k * 2 + 1);
arb[k] = max(arb[k * 2], arb[k * 2 + 1]);
}
int query(int a, int b, int x, int y, int k)
{
int mid = (x + y) / 2, e1 = -1, e2 = -1;
if (x == a && b == y)
return arb[k];
if (a <= mid)
e1 = query(a, min(b, mid), x, mid, k * 2);
if (b > mid)
e2 = query(max(mid + 1, a), b, mid + 1, y, k * 2 + 1);
return max(e1, e2);
}
};
vector<int> G[100010];
int val[100010];
class HLD
{
int levels[100010];
int subtree_nr[100010];
int father[100010];
int where[100010];
pair<int, int> segments[100010];
segment_tree hld_comps[100010];
vector<int> hld_vec[100010];
vector<int> hld_graph[100010];
int nr_comps;
void level_subtree_nr(int x, int f, int level, vector<int> G[])
{
levels[x] = level;
subtree_nr[x]++;
for (int i = 0; i < G[x].size(); ++i)
{
if (G[x][i] != f)
{
level_subtree_nr(G[x][i], x, level + 1, G);
subtree_nr[x] += subtree_nr[G[x][i]];
}
}
}
void form_hld_vec(int x, int f, int nr, vector<int> G[], int val[])
{
hld_vec[nr].push_back(val[x]);
where[x] = nr;
int ok = 1;
for (int i = 0; i < G[x].size(); ++i)
{
if (G[x][i] != f)
{
if (subtree_nr[G[x][i]] > subtree_nr[x] / 2)
{
ok = 0;
form_hld_vec(G[x][i], x, nr, G, val);
}
else
{
nr_comps++;
hld_graph[nr].push_back(nr_comps);
hld_graph[nr_comps].push_back(nr);
father[nr_comps] = nr;
segments[nr_comps].first = levels[G[x][i]];
form_hld_vec(G[x][i], x, nr_comps, G, val);
}
}
}
if (ok)
segments[nr].second = levels[x];
}
void form_hld()
{
for (int i = 0; i <= nr_comps; ++i)
{
hld_comps[i].create(hld_vec[i]);
}
}
public:
void create(vector<int> G[], int val[])
{
level_subtree_nr(1, 0, 0, G);
form_hld_vec(1, 0, 0, G, val);
form_hld();
}
void update(int x, int v)
{
int end = hld_vec[where[x]].size();
hld_comps[where[x]].update(levels[x] - segments[where[x]].first + 1, 1, end, v, 1);
}
int query(int x, int y)
{
int lv_x = levels[x];
int lv_y = levels[y];
int comp_x = where[x];
int comp_y = where[y];
auto lv_comp_x = segments[comp_x];
auto lv_comp_y = segments[comp_y];
int mx = 0;
while (comp_x != comp_y)
{
if (lv_comp_x <= lv_comp_y)
{
mx = max(mx, hld_comps[comp_y].query(1, lv_y - lv_comp_y.first + 1, 1, lv_comp_y.second - lv_comp_y.first + 1, 1));
lv_y = lv_comp_y.first - 1;
comp_y = father[comp_y];
}
else
{
mx = max(mx, hld_comps[comp_x].query(1, lv_x - lv_comp_x.first +1, 1, lv_comp_x.second - lv_comp_x.first + 1, 1));
lv_x = lv_comp_x.first - 1;
comp_x = father[comp_x];
}
lv_comp_x = segments[comp_x];
lv_comp_y = segments[comp_y];
}
if (lv_x > lv_y)
swap(lv_x, lv_y);
mx = max(mx, hld_comps[comp_x].query(lv_x - lv_comp_x.first + 1, lv_y - lv_comp_y.first +1, 1, lv_comp_x.second - lv_comp_x.first + 1, 1));
return mx;
}
};
HLD hld;
int main()
{
int N, Q;
in >> N >> Q;
for (int i = 1; i <= N; ++i)
{
int v;
in >> v;
val[i] = v;
}
for (int i = 1; i <= N-1; ++i)
{
int x, y;
in >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
hld.create(G, val);
for (int i = 1; i <= Q; ++i)
{
int t, x, y;
in >> t >> x >> y;
if (t == 0)
{
hld.update(x, y);
}
else
{
out << hld.query(x, y) << "\n";
}
}
return 0;
}