// vezi: https://cp-algorithms.com/graph/hld.html
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
// returns size of subtree
int dfs(int v, const vector<vector<int>> &adj,
vector<int> &parent, vector<int> &depth, vector<int> &heavy);
void decompose(int v, int h,
const vector<vector<int>> &adj, const vector<int> &parent,
vector<int> &heavy, vector<int> &head, vector<int> &pos,
int &curr_aint_pos);
void segtree_update(int index, int left, int right, int pos, int val,
vector<int> &tree);
int segtree_query(int index, int left, int right, int qleft, int qright,
const vector<int> &tree);
int query(int x, int y, int n,
const vector<int> &head, const vector<int> &pos,
const vector<int> &depth, const vector<int> &parent,
const vector<int> &segtree);
int main()
{
ifstream fin("heavypath.in");
ofstream fout("heavypath.out");
//ifstream fin("input.txt");
//ofstream fout("output.txt");
int n, m;
fin >> n >> m;
vector<int> v(n+1);
for (int i = 1; i <= n; i++)
fin >> v[i];
vector<vector<int>> adj(n+1);
for (int i = 1; i <= n-1; i++) {
int a, b;
fin >> a >> b;
adj[a].push_back(b);
adj[b].push_back(a);
}
vector<int> parent(n+1, 0);
parent[1] = 1; // rădăcina
vector<int> depth(n+1, 0); // adâncimea în arbore
vector<int> heavy(n+1, -1); // copilul care e legat
// cu heavy edge
vector<int> head(n+1, -1); // cel mai de sus nod
// din lanțul nodului
vector<int> segtree(4*n + 10, 0); // arbint
vector<int> pos(n+1); // poziția nodului în arbint
dfs(1, adj, parent, depth, heavy);
int curr_aint_pos = 1;
decompose(1, 1, adj, parent, heavy, head, pos, curr_aint_pos);
for (int i = 1; i <= n; i++)
segtree_update(1, 1, n, pos[i], v[i], segtree);
/*for (int i = 1; i <= n; i++)
fout << head[i] << " " << pos[i] << endl;
fout << "--------------\n";*/
for (int i = 0; i < m; i++) {
int t, x, y;
fin >> t >> x >> y;
if (t == 0) {
v[x] = y;
segtree_update(1, 1, n, pos[x], v[x], segtree);
}
else {
int res = query(x, y, n, head, pos, depth, parent, segtree);
fout << res << endl;
}
}
return 0;
}
int dfs(int v, const vector<vector<int>> &adj,
vector<int> &parent, vector<int> &depth, vector<int> &heavy)
{
int v_size = 1;
int max_child_size = 0;
for (int c : adj[v]) {
if (c != parent[v]) {
parent[c] = v;
depth[c] = depth[v] + 1;
int c_size = dfs(c, adj, parent, depth, heavy);
v_size += c_size;
if (c_size > max_child_size) {
max_child_size = c_size;
heavy[v] = c;
}
}
}
return v_size;
}
void decompose(int v, int h,
const vector<vector<int>> &adj, const vector<int> &parent,
vector<int> &heavy, vector<int> &head, vector<int> &pos,
int &curr_aint_pos)
{
head[v] = h;
pos[v] = curr_aint_pos;
curr_aint_pos++;
if (heavy[v] != -1) {
decompose(heavy[v], h,
adj, parent, heavy, head, pos, curr_aint_pos);
}
for (int c : adj[v]) {
if (c != parent[v] && c != heavy[v]) {
decompose(c, c,
adj, parent, heavy, head, pos, curr_aint_pos);
}
}
}
int query(int x, int y, int n,
const vector<int> &head, const vector<int> &pos,
const vector<int> &depth, const vector<int> &parent,
const vector<int> &segtree)
{
int res = 0;
while (head[x] != head[y]) {
if (depth[head[x]] > depth[head[y]])
swap(x, y);
int path_max = segtree_query(1, 1, n,
pos[head[y]], pos[y], segtree);
if (path_max > res)
res = path_max;
y = parent[head[y]];
}
if (depth[x] > depth[y])
swap(x, y);
int last_path = segtree_query(1, 1, n, pos[x], pos[y], segtree);
if (last_path > res)
res = last_path;
return res;
}
void segtree_update(int index, int left, int right, int pos, int val,
vector<int> &tree)
{
if (pos > right || pos < left)
return;
if (left == right) {
tree[index] = val;
return;
}
int mid = (left + right) / 2;
segtree_update(2*index, left, mid, pos, val, tree);
segtree_update(2*index+1, mid+1, right, pos, val, tree);
tree[index] = max(tree[2*index], tree[2*index+1]);
}
int segtree_query(int index, int left, int right, int qleft, int qright,
const vector<int> &tree)
{
if (qleft > right || qright < left)
return -1;
if (qleft <= left && qright >= right)
return tree[index];
int mid = (left + right) / 2;
int r1 = segtree_query(2*index, left, mid, qleft, qright, tree);
int r2 = segtree_query(2*index+1, mid+1, right, qleft, qright, tree);
return max(r1, r2);
}