Problem p01564 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <list>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define INF (1 << 30)

class DouseTree {
  friend class HLDecomposition;
  struct A {
    int left, right, ans, all;
    bool lazyflag;
    int lazyval;
    A &reverse() {
      std::swap(left, right);
      return *this;
    }
  };
  int n;
  mutable std::vector<A> node;
  void update(int a, int b, int x, int k, int l, int r) {
    if (r <= a || b <= l)
      return;
    if (a <= l && r <= b) {
      A &v = node[k];
      v.left = v.right = v.ans = x <= 0 ? x : x * (r - l);
      v.all = x * (r - l);
      v.lazyflag = true;
      v.lazyval = x;
      return;
    }
    int m = (l + r) / 2;
    if (node[k].lazyflag) {
      update(l, r, node[k].lazyval, 2 * k + 1, l, m);
      update(l, r, node[k].lazyval, 2 * k + 2, m, r);
      node[k].lazyflag = false;
    }
    update(a, b, x, 2 * k + 1, l, m);
    update(a, b, x, 2 * k + 2, m, r);
    node[k] = func(node[2 * k + 1], node[2 * k + 2]);
  }
  A query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l)
      return identity();
    if (a <= l && r <= b) {
      return node[k];
    }
    int m = (l + r) / 2;
    if (node[k].lazyflag) {
      update(l, r, node[k].lazyval, 2 * k + 1, l, m);
      update(l, r, node[k].lazyval, 2 * k + 2, m, r);
      node[k].lazyflag = false;
    }
    return func(query(a, b, 2 * k + 1, l, m), query(a, b, 2 * k + 2, m, r));
  }

public:
  static A identity() {
    A res = {-INF, -INF, -INF, 0, false};
    return res;
  }
  static A func(const A &a, const A &b) {
    if (a.left == -INF)
      return b;
    if (b.left == -INF)
      return a;
    A res;
    res.left = max(a.left, a.all + b.left);
    res.right = max(b.right, a.right + b.all);
    res.ans = max(max(a.ans, b.ans), a.right + b.left);
    res.all = a.all + b.all;
    res.lazyflag = false;
    return res;
  }
  DouseTree(int n) { init(n); }
  void init(int n) {
    while (n & (n - 1))
      n += n & -n;
    this->n = n;
    node.assign(2 * n - 1, identity());
  }
  void update(int a, int b, int x) { update(a, b, x, 0, 0, n); }
  A query(int a, int b) { return query(a, b, 0, 0, n); }
};

class LCA {
  int lg, n;
  vector<int> _depth, par;
  void bfs(const vector<int> edge[], int root) {
    queue<pair<int, int>> q;
    q.push(make_pair(root, 1));
    while (!q.empty()) {
      pair<int, int> pi = q.front();
      int u = pi.first;
      _depth[u] = pi.second;
      q.pop();
      for (int i = 0; i < (int)edge[u].size(); i++) {
        q.push(make_pair(edge[u][i], pi.second + 1));
      }
    }
  }
  void init(const vector<int> &parent) {
    lg = 1;
    while ((1 << lg) < n)
      lg++;
    lg++;
    par.resize(n * lg);
    for (int i = 0; i < n; i++)
      par[i] = parent[i];
    for (int i = 1; i < lg; i++)
      for (int v = 0; v < n; v++)
        if (par[(i - 1) * n + v] != -1)
          par[i * n + v] = par[(i - 1) * n + par[(i - 1) * n + v]];
        else
          par[i * n + v] = -1;
  }

public:
  LCA(const vector<int> edge[], int n) : n(n), _depth(n, 0) {
    vector<int> parent(n, -1);
    for (int i = 0; i < n; i++)
      for (int j = 0; j < (int)edge[i].size(); j++)
        parent[edge[i][j]] = i;
    bfs(edge, find(parent.begin(), parent.end(), -1) - parent.begin());
    init(parent);
  }
  int query(int u, int v) const {
    if (_depth[u] > _depth[v])
      std::swap(u, v);
    for (int i = lg - 1; i >= 0; i--)
      if (_depth[u] <= _depth[v] - (1 << i))
        v = par[i * n + v];
    if (u == v)
      return u;
    for (int i = lg - 1; i >= 0; i--) {
      if (par[i * n + u] != par[i * n + v]) {
        u = par[i * n + u];
        v = par[i * n + v];
      }
    }
    return par[u];
  }
  int depth(int u) const { // rootの深さが1
    return _depth[u];
  }
};

class HLDecomposition {
  struct S {
    pair<int, int> par;
    DouseTree segtree;
    S(int a, int b, vector<int> v) : par(a, b), segtree(v.size()) {
      for (int i = 0; i < (int)v.size(); i++) {
        segtree.update(i, i + 1, v[i]);
      }
    }
  };
  void max_subtree(int u, vector<int> edge[], vector<int> &msz) {
    stack<int> st;
    vector<int> size(msz.size());
    st.push(u);
    while (!st.empty()) {
      u = st.top();
      st.pop();
      if (u < 0) {
        u = -u - 1;
        int res = 0, sz = 0, idx = -1;
        for (int i = 0; i < (int)edge[u].size(); i++) {
          int s = size[edge[u][i]];
          if (sz < s) {
            sz = s;
            idx = i;
          }
          res += s;
        }
        size[u] = res + 1;
        msz[u] = idx;
      } else {
        st.push(-u - 1);
        for (int i = 0; i < (int)edge[u].size(); i++) {
          st.push(edge[u][i]);
        }
      }
    }
  }
  void build(int u, vector<int> edge[], int val[], vector<int> &msz) {
    vector<int> heavy;
    int v = u;
    int par = compressed.size(), pi = 0, s;
    while (1) {
      ver[v] = make_pair(par, heavy.size());
      heavy.push_back(val[v]);
      if (msz[v] == -1)
        break;
      v = edge[v][msz[v]];
    }
    compressed.push_back(S(-1, -1, heavy));
    heavy.clear();
    while (1) {
      for (int i = 0; i < (int)edge[u].size(); i++) {
        if (i == msz[u])
          continue;
        s = compressed.size();
        build(edge[u][i], edge, val, msz);
        compressed[s].par = make_pair(par, pi);
      }
      if (msz[u] == -1)
        break;
      u = edge[u][msz[u]];
      pi++;
    }
  }
  mutable vector<S> compressed;
  vector<pair<int, int>> ver;
  LCA lca;

public:
  HLDecomposition(vector<int> edge[], int val[], int n) : ver(n), lca(edge, n) {
    vector<int> maxsz(n, -1);
    max_subtree(0, edge, maxsz);
    build(0, edge, val, maxsz);
  }
  long long query(int u, int v) const {
    int w = lca.query(u, v);
    pair<int, int> a, b, c;
    a = ver[u];
    b = ver[v];
    c = ver[w];
    DouseTree::A res1, res2;
    res1 = res2 = DouseTree::identity();
    while (c.first != a.first) {
      res1 = DouseTree::func(
          res1, compressed[a.first].segtree.query(0, a.second + 1).reverse());
      a = compressed[a.first].par;
    }
    res1 = DouseTree::func(
        res1,
        compressed[c.first].segtree.query(c.second, a.second + 1).reverse());
    while (c.first != b.first) {
      res2 = DouseTree::func(compressed[b.first].segtree.query(0, b.second + 1),
                             res2);
      b = compressed[b.first].par;
    }
    res2 = DouseTree::func(
        compressed[c.first].segtree.query(c.second + 1, b.second + 1), res2);
    return DouseTree::func(res1, res2).ans;
  }
  void update(int u, int v, int x) const {
    int w = lca.query(u, v);
    pair<int, int> a, b, c;
    a = ver[u];
    b = ver[v];
    c = ver[w];
    while (c.first != a.first) {
      compressed[a.first].segtree.update(0, a.second + 1, x);
      a = compressed[a.first].par;
    }
    compressed[c.first].segtree.update(c.second, a.second + 1, x);
    while (c.first != b.first) {
      compressed[b.first].segtree.update(0, b.second + 1, x);
      b = compressed[b.first].par;
    }
    compressed[c.first].segtree.update(c.second + 1, b.second + 1, x);
  }
};

// uを根とする木の親への辺を削除
void tree_delete_edge(int u, vector<int> edge[], int par = -1) {
  queue<pair<int, int>> q;
  q.push(make_pair(u, -1));
  while (!q.empty()) {
    pair<int, int> pi = q.front();
    u = pi.first;
    q.pop();
    for (int i = 0; i < (int)edge[u].size(); i++) {
      if (edge[u][i] == pi.second) {
        edge[u].erase(edge[u].begin() + i--);
      } else {
        q.push(make_pair(edge[u][i], u));
      }
    }
  }
}

int val[200000];
vector<int> edge[200000];

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n, q;
  cin >> n >> q;
  for (int i = 0; i < n; i++)
    cin >> val[i];
  for (int i = 0; i < n - 1; i++) {
    int s, e;
    cin >> s >> e;
    s--;
    e--;
    edge[s].push_back(e);
    edge[e].push_back(s);
  }
  tree_delete_edge(0, edge);
  HLDecomposition hl(edge, val, n);
  for (int i = 0; i < q; i++) {
    int t, a, b, c;
    cin >> t >> a >> b >> c;
    a--;
    b--;
    if (t == 1) {
      hl.update(a, b, c);
    } else {
      cout << hl.query(a, b) << endl;
    }
  }
  return 0;
}

Error: 0

Fixed submission:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <list>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define INF (1 << 29)

class DouseTree {
  friend class HLDecomposition;
  struct A {
    int left, right, ans, all;
    bool lazyflag;
    int lazyval;
    A &reverse() {
      std::swap(left, right);
      return *this;
    }
  };
  int n;
  mutable std::vector<A> node;
  void update(int a, int b, int x, int k, int l, int r) {
    if (r <= a || b <= l)
      return;
    if (a <= l && r <= b) {
      A &v = node[k];
      v.left = v.right = v.ans = x <= 0 ? x : x * (r - l);
      v.all = x * (r - l);
      v.lazyflag = true;
      v.lazyval = x;
      return;
    }
    int m = (l + r) / 2;
    if (node[k].lazyflag) {
      update(l, r, node[k].lazyval, 2 * k + 1, l, m);
      update(l, r, node[k].lazyval, 2 * k + 2, m, r);
      node[k].lazyflag = false;
    }
    update(a, b, x, 2 * k + 1, l, m);
    update(a, b, x, 2 * k + 2, m, r);
    node[k] = func(node[2 * k + 1], node[2 * k + 2]);
  }
  A query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l)
      return identity();
    if (a <= l && r <= b) {
      return node[k];
    }
    int m = (l + r) / 2;
    if (node[k].lazyflag) {
      update(l, r, node[k].lazyval, 2 * k + 1, l, m);
      update(l, r, node[k].lazyval, 2 * k + 2, m, r);
      node[k].lazyflag = false;
    }
    return func(query(a, b, 2 * k + 1, l, m), query(a, b, 2 * k + 2, m, r));
  }

public:
  static A identity() {
    A res = {-INF, -INF, -INF, 0, false};
    return res;
  }
  static A func(const A &a, const A &b) {
    A res;
    res.left = max(a.left, a.all + b.left);
    res.right = max(b.right, a.right + b.all);
    res.ans = max(max(a.ans, b.ans), a.right + b.left);
    res.all = a.all + b.all;
    res.lazyflag = false;
    return res;
  }
  DouseTree(int n) { init(n); }
  void init(int n) {
    while (n & (n - 1))
      n += n & -n;
    this->n = n;
    node.assign(2 * n - 1, identity());
  }
  void update(int a, int b, int x) { update(a, b, x, 0, 0, n); }
  A query(int a, int b) { return query(a, b, 0, 0, n); }
};

class LCA {
  int lg, n;
  vector<int> _depth, par;
  int dfs(const vector<int> &parent, int u) {
    if (parent[u] == -1)
      return _depth[u] = 1;
    if (_depth[u] != 0)
      return _depth[u];
    return _depth[u] = dfs(parent, parent[u]) + 1;
  }
  void init(const vector<int> &parent) {
    lg = 1;
    while ((1 << lg) < n)
      lg++;
    lg++;
    for (int i = 0; i < n; i++)
      dfs(parent, i);
    par.resize(n * lg);
    for (int i = 0; i < n; i++)
      par[i] = parent[i];
    for (int i = 1; i < lg; i++)
      for (int v = 0; v < n; v++)
        if (par[(i - 1) * n + v] != -1)
          par[i * n + v] = par[(i - 1) * n + par[(i - 1) * n + v]];
        else
          par[i * n + v] = -1;
  }

public:
  LCA(const vector<int> &parent) : n(parent.size()), _depth(parent.size(), 0) {
    init(parent);
  }
  LCA(const int parent[], int n) { LCA(vector<int>(parent, parent + n)); }
  LCA(const vector<int> edge[], int n) : n(n), _depth(n, 0) {
    vector<int> parent(n, -1);
    for (int i = 0; i < n; i++)
      for (int j = 0; j < (int)edge[i].size(); j++)
        parent[edge[i][j]] = i;
    init(parent);
  }
  int query(int u, int v) const {
    if (_depth[u] > _depth[v])
      std::swap(u, v);
    for (int i = lg - 1; i >= 0; i--)
      if (_depth[u] <= _depth[v] - (1 << i))
        v = par[i * n + v];
    if (u == v)
      return u;
    for (int i = lg - 1; i >= 0; i--) {
      if (par[i * n + u] != par[i * n + v]) {
        u = par[i * n + u];
        v = par[i * n + v];
      }
    }
    return par[u];
  }
  int depth(int u) const { // rootの深さが1
    return _depth[u];
  }
};

class HLDecomposition {
  struct S {
    pair<int, int> par;
    DouseTree segtree;
    S(int a, int b, vector<int> v) : par(a, b), segtree(v.size()) {
      for (int i = 0; i < (int)v.size(); i++) {
        segtree.update(i, i + 1, v[i]);
      }
    }
  };
  void max_subtree(int u, vector<int> edge[], vector<int> &msz) {
    stack<int> st;
    vector<int> size(msz.size());
    st.push(u);
    while (!st.empty()) {
      u = st.top();
      st.pop();
      if (u < 0) {
        u = -u - 1;
        int res = 0, sz = 0, idx = -1;
        for (int i = 0; i < (int)edge[u].size(); i++) {
          int s = size[edge[u][i]];
          if (sz < s) {
            sz = s;
            idx = i;
          }
          res += s;
        }
        size[u] = res + 1;
        msz[u] = idx;
      } else {
        st.push(-u - 1);
        for (int i = 0; i < (int)edge[u].size(); i++) {
          st.push(edge[u][i]);
        }
      }
    }
  }
  void build(int u, vector<int> edge[], int val[], vector<int> &msz) {
    vector<int> heavy;
    int v = u;
    int par = compressed.size(), pi = 0, s;
    while (1) {
      ver[v] = make_pair(par, heavy.size());
      heavy.push_back(val[v]);
      if (msz[v] == -1)
        break;
      v = edge[v][msz[v]];
    }
    compressed.push_back(S(-1, -1, heavy));
    heavy.clear();
    while (1) {
      for (int i = 0; i < (int)edge[u].size(); i++) {
        if (i == msz[u])
          continue;
        s = compressed.size();
        build(edge[u][i], edge, val, msz);
        compressed[s].par = make_pair(par, pi);
      }
      if (msz[u] == -1)
        break;
      u = edge[u][msz[u]];
      pi++;
    }
  }
  mutable vector<S> compressed;
  vector<pair<int, int>> ver;
  LCA lca;

public:
  HLDecomposition(vector<int> edge[], int val[], int n) : ver(n), lca(edge, n) {
    vector<int> maxsz(n, -1);
    max_subtree(0, edge, maxsz);
    build(0, edge, val, maxsz);
  }
  long long query(int u, int v) const {
    int w = lca.query(u, v);
    pair<int, int> a, b, c;
    a = ver[u];
    b = ver[v];
    c = ver[w];
    DouseTree::A res1, res2;
    res1 = res2 = DouseTree::identity();
    while (c.first != a.first) {
      res1 = DouseTree::func(
          res1, compressed[a.first].segtree.query(0, a.second + 1).reverse());
      a = compressed[a.first].par;
    }
    res1 = DouseTree::func(
        res1,
        compressed[c.first].segtree.query(c.second, a.second + 1).reverse());
    while (c.first != b.first) {
      res2 = DouseTree::func(compressed[b.first].segtree.query(0, b.second + 1),
                             res2);
      b = compressed[b.first].par;
    }
    res2 = DouseTree::func(
        compressed[c.first].segtree.query(c.second + 1, b.second + 1), res2);
    return DouseTree::func(res1, res2).ans;
  }
  void update(int u, int v, int x) const {
    int w = lca.query(u, v);
    pair<int, int> a, b, c;
    a = ver[u];
    b = ver[v];
    c = ver[w];
    while (c.first != a.first) {
      compressed[a.first].segtree.update(0, a.second + 1, x);
      a = compressed[a.first].par;
    }
    compressed[c.first].segtree.update(c.second, a.second + 1, x);
    while (c.first != b.first) {
      compressed[b.first].segtree.update(0, b.second + 1, x);
      b = compressed[b.first].par;
    }
    compressed[c.first].segtree.update(c.second + 1, b.second + 1, x);
  }
};

// uを根とする木の親への辺を削除
void tree_delete_edge(int u, vector<int> edge[], int par = -1) {
  for (int i = 0; i < (int)edge[u].size(); i++) {
    if (edge[u][i] == par) {
      edge[u].erase(edge[u].begin() + i--);
    } else {
      tree_delete_edge(edge[u][i], edge, u);
    }
  }
}

int val[200000];
vector<int> edge[200000];

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n, q;
  cin >> n >> q;
  for (int i = 0; i < n; i++)
    cin >> val[i];
  for (int i = 0; i < n - 1; i++) {
    int s, e;
    cin >> s >> e;
    s--;
    e--;
    edge[s].push_back(e);
    edge[e].push_back(s);
  }
  tree_delete_edge(0, edge);
  HLDecomposition hl(edge, val, n);
  for (int i = 0; i < q; i++) {
    int t, a, b, c;
    cin >> t >> a >> b >> c;
    a--;
    b--;
    if (t == 1) {
      hl.update(a, b, c);
    } else {
      cout << hl.query(a, b) << endl;
    }
  }
  return 0;
}