Cod sursa(job #2691879)

Utilizator retrogradLucian Bicsi retrograd Data 30 decembrie 2020 14:02:11
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.05 kb
#ifdef LOCAL
#include <debug.hpp>
#else
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,tune=native")
#define debug(...)
#endif 

#include <bits/stdc++.h>

using namespace std;

struct SegTree {
  vector<int> T; int n;
  SegTree(int n) : T(2 * n, (int)-2e9), n(n) {}
  
  void Update(int pos, int val) {
    for (T[pos += n] = val; pos > 1; pos /= 2)
      T[pos / 2] = max(T[pos], T[pos ^ 1]);
  }
  int Query(int b, int e) {
    int res = -2e9;
    for (b += n, e += n; b < e; b /= 2, e /= 2) {
      if (b % 2) res = max(res, T[b++]);
      if (e % 2) res = max(res, T[--e]);
    }
    return res;
  }
};

struct HeavyLight {
  vector<int> jump, sub, depth, enter, parent;
  vector<vector<int>> graph;
  int timer = 0;
  
  HeavyLight(int n) : 
      jump(n), sub(n), depth(n), 
      enter(n), parent(n), graph(n) {}
  
  void AddEdge(int a, int b) {
    graph[a].push_back(b);
    graph[b].push_back(a);
  }
  void Build(int root) {
    dfs1(root, -1, 0); dfs2(root, root);
  }
  // Returns the position in the HL linearization
  int GetPos(int node) {
    assert(timer); // Call Build() before
    return enter[node];
  }
  // Computes an array of ranges of form [li...ri)
  // that correspond to the ranges you would need
  // to query in the underlying structure
  void GetRanges(int a, int b, vector<pair<int, int>>& ret) {
    assert(timer); // Call Build() before
    while (jump[a] != jump[b]) {
      if (depth[jump[a]] < depth[jump[b]]) swap(a, b);
      ret.emplace_back(enter[jump[a]], enter[a] + 1);
      a = parent[jump[a]];
    }
    if (depth[a] < depth[b]) swap(a, b);
    ret.emplace_back(enter[b], enter[a] + 1);
  }
  int dfs1(int node, int par, int dep) {
    sub[node] = 1; parent[node] = par; depth[node] = dep;
    if (par != -1) 
      graph[node].erase(
        find(graph[node].begin(), graph[node].end(), par));
    for (auto vec : graph[node])
      sub[node] += dfs1(vec, node, dep + 1);
    return sub[node];
  }
  void dfs2(int node, int jmp) {
    jump[node] = jmp; enter[node] = timer++;
    iter_swap(graph[node].begin(), max_element(
      graph[node].begin(), graph[node].end(), 
        [&](int a, int b) { return sub[a] < sub[b]; }
    ));
    for (auto vec : graph[node])
      dfs2(vec, vec == graph[node].front() ? jmp : vec);
  }
};

int main() {
  ifstream cin("heavypath.in");
  ofstream cout("heavypath.out");

  int n, q; cin >> n >> q;
  vector<int> v(n);
  for (int i = 0; i < n; ++i)
    cin >> v[i];
  HeavyLight H(n);
  for (int i = 1; i < n; ++i) {
    int a, b; cin >> a >> b; 
    H.AddEdge(a - 1, b - 1);
  }
  H.Build(0);
  SegTree st(n);
  for (int i = 0; i < n; ++i)
    st.Update(H.GetPos(i), v[i]);
  vector<pair<int, int>> ranges;
  for (int i = 0; i < q; ++i) {
    int t, a, b; cin >> t >> a >> b;
    if (t == 0) st.Update(H.GetPos(a - 1), b);
    else {
      H.GetRanges(a - 1, b - 1, ranges);
      int ans = -2e9;
      for (auto itr : ranges)
        ans = max(ans, st.Query(itr.first, itr.second));
      cout << ans << '\n';
      ranges.clear();
    }
  }
  return 0;
}