Link to this code:
https://cses.fi/paste/e320b46ce2617bde1185f04/#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9, LG = 18, inf = 1e9 + 9;
int n;
struct ST {
#define lc (n << 1)
#define rc ((n << 1) | 1)
int t[4 * N];
ST() {
fill(t, t + 4 * N, -inf);
}
inline int combine(int a, int b) {
return max(a, b); //merge left and right queries
}
inline void pull(int n) {
t[n] = max(t[lc], t[rc]); //merge lower nodes of the tree to get the parent node
}
void build(int n, int b, int e, vector<int> &a) {
if(b == e) {
t[n] = a[b];
return;
}
int mid = (b + e) >> 1;
build(lc, b, mid, a);
build(rc, mid + 1, e, a);
pull(n);
}
void upd(int n, int b, int e, int i, int v) {
if(b == e) {
t[n] = v;
return;
}
int mid = (b + e) >> 1;
if(i <= mid) upd(lc, b, mid, i, v);
else upd(rc, mid + 1, e, i, v);
pull(n);
}
int query(int n, int b, int e, int i, int j) {
if(i > e || b > j) return -inf;
if(i <= b && e <= j) return t[n];
int mid = (b + e) >> 1;
return combine(query(lc, b, mid, i, j), query(rc, mid + 1, e, i, j));
}
} t;
vector<int> g[N];
int par[N][LG + 1], dep[N], sz[N];
void dfs(int root) {
vector<int> order;
order.reserve(n);
stack<int> s;
s.push(root);
par[root][0] = 0;
dep[root] = 1;
while(!s.empty()) {
int u = s.top();
s.pop();
order.push_back(u);
for(auto v : g[u]) if(v != par[u][0]) {
par[v][0] = u;
dep[v] = dep[u] + 1;
for(int i = 1; i <= LG; i++)
par[v][i] = par[par[v][i - 1]][i - 1];
s.push(v);
}
}
reverse(order.begin(), order.end());
for(auto u : order) {
sz[u] = 1;
int heavy = -1;
for(auto v : g[u]) {
if(par[v][0] != u) continue;
sz[u] += sz[v];
if(heavy == -1 || sz[v] > sz[heavy])
heavy = v;
}
if(heavy != -1) {
auto it = find(g[u].begin(), g[u].end(), heavy);
iter_swap(g[u].begin(), it);
}
}
}
int lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
for (int k = LG; k >= 0; k--) if (dep[par[u][k]] >= dep[v]) u = par[u][k];
if (u == v) return u;
for (int k = LG; k >= 0; k--) if (par[u][k] != par[v][k])
u = par[u][k], v = par[v][k];
return par[u][0];
}
int kth(int u, int k) {
assert(k >= 0);
for (int i = 0; i <= LG; i++)
if (k & (1 << i)) u = par[u][i];
return u;
}
int T, head[N], st[N], en[N];
void dfs_hld(int root) {
stack<pair<int, int>> s;
s.push({root, root});
while(!s.empty()) {
int u = s.top().first;
int h = s.top().second;
s.pop();
while(u) {
head[u] = h;
st[u] = ++T;
for(int i = (int)g[u].size() - 1; i >= 0; i--) {
int v = g[u][i];
if(v == par[u][0] || v == g[u][0]) continue;
s.push({v, v});
}
if(g[u].empty() || g[u][0] == par[u][0]) break;
u = g[u][0];
}
}
for(int u = 1; u <= n; u++)
en[u] = st[u] + sz[u] - 1;
}
int query_up(int u, int v) {
int ans = -inf;
while(head[u] != head[v]) {
ans = max(ans, t.query(1, 1, n, st[head[u]], st[u]));
u = par[head[u]][0];
}
ans = max(ans, t.query(1, 1, n, st[v], st[u]));
return ans;
}
int query(int u, int v) {
int l = lca(u, v);
int ans = query_up(u, l);
if (v != l)
ans = max(ans, query_up(v, kth(v, dep[v] - dep[l] - 1)));
return ans;
}
int32_t main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int q;
cin >> n >> q;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1);
dfs_hld(1);
for(int i = 1; i <= n; i++)
b[st[i]] = a[i];
t.build(1, 1, n, b);
while(q--) {
int ty;
cin >> ty;
if(ty == 1) {
int s, x;
cin >> s >> x;
t.upd(1, 1, n, st[s], x);
} else {
int u, v;
cin >> u >> v;
cout << query(u, v) << '\n';
}
}
return 0;
}