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

#include <cassert>
#include <utility>
#include <vector>

template <typename ValueMonoid, typename OperatorMonoid, class Modify>
class LinkCutTree {
public:
  using value_type = ValueMonoid;
  using operator_type = OperatorMonoid;

private:
  struct node_t {
    node_t *left, *right, *par;
    value_type value, sum;
    operator_type lazy;
    bool isroot, reversed;
    node_t()
        : left(nullptr), right(nullptr), par(nullptr), value(), sum(), lazy(),
          isroot(1), reversed(0) {}
    bool isleft() const { return par->left == this; }
    void assign(const operator_type &data) { lazy = lazy + data; }
    void haulL(node_t *const t) {
      left = t;
      if (t)
        t->par = this;
    }
    void haulR(node_t *const t) {
      right = t;
      if (t)
        t->par = this;
    }
  };
  value_type reflect(const node_t *const t) const {
    if (!t)
      return value_type();
    if (t->reversed)
      return m(~t->sum, t->lazy);
    return m(t->sum, t->lazy);
  }
  void recalc(node_t *const t) {
    t->sum = reflect(t->left) + t->value + reflect(t->right);
  }
  void splay(node_t *const t) {
    node_t *p, *pp = t, *x = t->par;
    while (!t->isroot) {
      if (x->left == pp)
        x->left = t;
      else
        x->right = t;
      p = t->par;
      if (p->isroot) {
        t->par = p->par;
        std::swap(t->isroot, p->isroot);
        if (p->left == t) {
          p->haulL(t->right);
          t->haulR(p);
        } else {
          p->haulR(t->left);
          t->haulL(p);
        }
        recalc(p);
        break;
      }
      pp = p->par;
      x = pp->par;
      std::swap(t->isroot, pp->isroot);
      if (t->isleft()) {
        if (p->isleft()) {
          pp->haulL(p->right);
          p->haulR(pp);
        } else {
          pp->haulR(t->left);
          t->haulL(pp);
        }
        p->haulL(t->right);
        t->haulR(p);
      } else {
        if (p->isleft()) {
          pp->haulL(t->right);
          t->haulR(pp);
        } else {
          pp->haulR(p->left);
          p->haulL(pp);
        }
        p->haulR(t->left);
        t->haulL(p);
      }
      recalc(pp);
      recalc(p);
      t->par = x;
    }
  }
  void push(node_t *const t) {
    if (t->left)
      t->left->assign(t->lazy);
    if (t->right)
      t->right->assign(t->lazy);
    t->value = m(t->value, t->lazy);
    t->lazy = operator_type();
    if (!t->reversed)
      return;
    std::swap(t->left, t->right);
    if (t->left)
      t->left->reversed ^= 1;
    if (t->right)
      t->right->reversed ^= 1;
    t->value = ~t->value;
    t->reversed = 0;
  }
  void propagate(node_t *t) {
    size_type it = 0;
    while (t) {
      st[it++] = t;
      t = t->par;
    }
    while (it)
      push(st[--it]);
  }
  void expose(node_t *const n) {
    propagate(n);
    node_t *x = n, *prev = nullptr;
    while (x) {
      splay(x);
      if (x->right)
        x->right->isroot = 1;
      x->right = prev;
      if (prev)
        prev->isroot = 0;
      recalc(x);
      prev = x;
      x = x->par;
    }
    splay(n);
    recalc(n);
  }
  using container_type = std::vector<node_t>;

public:
  using size_type = typename container_type::size_type;

private:
  container_type tree;
  std::vector<node_t *> st;
  const Modify m;
  void reroot(const size_type v) {
    expose(&tree[v]);
    tree[v].reversed ^= 1;
  }

public:
  explicit LinkCutTree(const size_type size, const Modify &m = Modify())
      : tree(size), m(m) {}
  explicit LinkCutTree(const std::vector<value_type> &a,
                       const Modify &m = Modify())
      : tree(a.size()), st(a.size() + 1), m(m) {
    for (size_type i = 0; i < a.size(); ++i)
      tree[i].value = tree[i].sum = a[i];
  }
  void link(const size_type child, const size_type parent) {
    assert(child < size());
    assert(parent < size());
    reroot(child);
    tree[child].par = &tree[parent];
  }
  void cut(const size_type child) {
    assert(child < size());
    node_t *const n = &tree[child];
    expose(n);
    if (n->left) {
      n->left->isroot = 1;
      n->left->par = nullptr;
    }
    n->left = nullptr;
    n->sum = n->value;
  }
  void update(const size_type u, const size_type v, const operator_type &data) {
    assert(u < size());
    assert(v < size());
    reroot(u);
    expose(&tree[v]);
    tree[v].assign(data);
  }
  value_type path(const size_type u, const size_type v) {
    assert(u < size());
    assert(v < size());
    reroot(u);
    expose(&tree[v]);
    return tree[v].sum;
  }
  size_type size() const noexcept { return tree.size(); }
  bool empty() const noexcept { return tree.empty(); }
};

#include <algorithm>
struct Ass {
  int a;
  bool f;
  Ass() : f(1) {}
  Ass(int a) : a(a), f(0) {}
  Ass operator+(const Ass &o) const { return o.f ? *this : o; }
};
struct Line {
  int all, l, r, max, siz;
  bool f;
  Line() : f(1) {}
  Line(int all, int l, int r, int max, int siz, bool f = 0)
      : all(all), l(l), r(r), max(max), siz(siz), f(f) {}
  Line operator~() const { return Line(all, r, l, max, siz, f); }
  Line operator+(const Line &o) const {
    if (f)
      return o;
    if (o.f)
      return *this;
    return Line(all + o.all, std::max(l, o.l > 0 ? all + o.l : all),
                std::max(o.r, r > 0 ? r + o.all : o.all),
                std::max(std::max(max, o.max), r + o.l), siz + o.siz);
  }
};
struct hoge {
  Line operator()(const Line &x, const Ass &y) const {
    if (y.f || x.f)
      return x;
    if (y.a > 0)
      return Line(y.a * x.siz, y.a * x.siz, y.a * x.siz, y.a * x.siz, x.siz);
    else
      return Line(y.a * x.siz, y.a, y.a, y.a, x.siz);
  }
};

#include <cstdio>
#include <vector>
int main(void) {
  int nn, q;
  scanf("%d %d", &nn, &q);
  const int n = nn;
  std::vector<Line> d;
  int w;
  for (int i = 0; i < n; ++i) {
    scanf("%d", &w);
    d.emplace_back(w, w, w, w, 1);
  }
  LinkCutTree<Line, Ass, hoge> T(d);
  int s, e;
  for (int i = 1; i < n; ++i) {
    scanf("%d %d", &s, &e);
    T.link(s - 1, e - 1);
  }
  int t, a, b;
  Ass c(0);
  while (q--) {
    scanf("%d %d %d %d", &t, &a, &b, &c.a);
    if (t == 1)
      T.update(a - 1, b - 1, c);
    else
      printf("%d\\n", T.path(a - 1, b - 1).max);
  }
  return 0;
}


Error: 0

Fixed submission:

#include <cassert>
#include <utility>
#include <vector>

template <typename ValueMonoid, typename OperatorMonoid, class Modify>
class LinkCutTree {
public:
  using value_type = ValueMonoid;
  using operator_type = OperatorMonoid;

private:
  struct node_t {
    node_t *left, *right, *par;
    value_type value, sum;
    operator_type lazy;
    bool isroot, reversed;
    node_t()
        : left(nullptr), right(nullptr), par(nullptr), value(), sum(), lazy(),
          isroot(1), reversed(0) {}
    bool isleft() const { return par->left == this; }
    void assign(const operator_type &data) { lazy = lazy + data; }
    void haulL(node_t *const t) {
      left = t;
      if (t)
        t->par = this;
    }
    void haulR(node_t *const t) {
      right = t;
      if (t)
        t->par = this;
    }
  };
  value_type reflect(const node_t *const t) const {
    if (!t)
      return value_type();
    if (t->reversed)
      return m(~t->sum, t->lazy);
    return m(t->sum, t->lazy);
  }
  void recalc(node_t *const t) {
    t->sum = reflect(t->left) + t->value + reflect(t->right);
  }
  void splay(node_t *const t) {
    node_t *p, *pp = t, *x = t->par;
    while (!t->isroot) {
      if (x->left == pp)
        x->left = t;
      else
        x->right = t;
      p = t->par;
      if (p->isroot) {
        t->par = p->par;
        std::swap(t->isroot, p->isroot);
        if (p->left == t) {
          p->haulL(t->right);
          t->haulR(p);
        } else {
          p->haulR(t->left);
          t->haulL(p);
        }
        recalc(p);
        break;
      }
      pp = p->par;
      x = pp->par;
      std::swap(t->isroot, pp->isroot);
      if (t->isleft()) {
        if (p->isleft()) {
          pp->haulL(p->right);
          p->haulR(pp);
        } else {
          pp->haulR(t->left);
          t->haulL(pp);
        }
        p->haulL(t->right);
        t->haulR(p);
      } else {
        if (p->isleft()) {
          pp->haulL(t->right);
          t->haulR(pp);
        } else {
          pp->haulR(p->left);
          p->haulL(pp);
        }
        p->haulR(t->left);
        t->haulL(p);
      }
      recalc(pp);
      recalc(p);
      t->par = x;
    }
  }
  void push(node_t *const t) {
    if (t->left)
      t->left->assign(t->lazy);
    if (t->right)
      t->right->assign(t->lazy);
    t->value = m(t->value, t->lazy);
    t->lazy = operator_type();
    if (!t->reversed)
      return;
    std::swap(t->left, t->right);
    if (t->left)
      t->left->reversed ^= 1;
    if (t->right)
      t->right->reversed ^= 1;
    t->value = ~t->value;
    t->reversed = 0;
  }
  void propagate(node_t *t) {
    size_type it = 0;
    st[0] = t;
    while (t)
      st[++it] = t = t->par;
    while (it)
      push(st[--it]);
  }
  void expose(node_t *const n) {
    propagate(n);
    node_t *x = n, *prev = nullptr;
    while (x) {
      splay(x);
      if (x->right)
        x->right->isroot = 1;
      x->right = prev;
      if (prev)
        prev->isroot = 0;
      recalc(x);
      prev = x;
      x = x->par;
    }
    splay(n);
    recalc(n);
  }
  using container_type = std::vector<node_t>;

public:
  using size_type = typename container_type::size_type;

private:
  container_type tree;
  std::vector<node_t *> st;
  const Modify m;
  void reroot(const size_type v) {
    expose(&tree[v]);
    tree[v].reversed ^= 1;
  }

public:
  explicit LinkCutTree(const size_type size, const Modify &m = Modify())
      : tree(size), m(m) {}
  explicit LinkCutTree(const std::vector<value_type> &a,
                       const Modify &m = Modify())
      : tree(a.size()), st(a.size()), m(m) {
    for (size_type i = 0; i < a.size(); ++i)
      tree[i].value = tree[i].sum = a[i];
  }
  void link(const size_type child, const size_type parent) {
    assert(child < size());
    assert(parent < size());
    reroot(child);
    tree[child].par = &tree[parent];
  }
  void cut(const size_type child) {
    assert(child < size());
    node_t *const n = &tree[child];
    expose(n);
    if (n->left) {
      n->left->isroot = 1;
      n->left->par = nullptr;
    }
    n->left = nullptr;
    n->sum = n->value;
  }
  void update(const size_type u, const size_type v, const operator_type &data) {
    assert(u < size());
    assert(v < size());
    reroot(u);
    expose(&tree[v]);
    tree[v].assign(data);
  }
  value_type path(const size_type u, const size_type v) {
    assert(u < size());
    assert(v < size());
    reroot(u);
    expose(&tree[v]);
    return tree[v].sum;
  }
  size_type size() const noexcept { return tree.size(); }
  bool empty() const noexcept { return tree.empty(); }
};

#include <algorithm>
struct Ass {
  int a;
  bool f;
  Ass() : f(1) {}
  Ass(int a) : a(a), f(0) {}
  Ass operator+(const Ass &o) const { return o.f ? *this : o; }
};
struct Line {
  int all, l, r, max, siz;
  bool f;
  Line() : f(1) {}
  Line(int all, int l, int r, int max, int siz, bool f = 0)
      : all(all), l(l), r(r), max(max), siz(siz), f(f) {}
  Line operator~() const { return Line(all, r, l, max, siz, f); }
  Line operator+(const Line &o) const {
    if (f)
      return o;
    if (o.f)
      return *this;
    return Line(all + o.all, std::max(l, o.l > 0 ? all + o.l : all),
                std::max(o.r, r > 0 ? r + o.all : o.all),
                std::max(std::max(max, o.max), r + o.l), siz + o.siz);
  }
};
struct hoge {
  Line operator()(const Line &x, const Ass &y) const {
    if (y.f || x.f)
      return x;
    if (y.a > 0)
      return Line(y.a * x.siz, y.a * x.siz, y.a * x.siz, y.a * x.siz, x.siz);
    else
      return Line(y.a * x.siz, y.a, y.a, y.a, x.siz);
  }
};

#include <cstdio>
#include <vector>
int main(void) {
  int nn, q;
  scanf("%d %d", &nn, &q);
  const int n = nn;
  std::vector<Line> d;
  int w;
  for (int i = 0; i < n; ++i) {
    scanf("%d", &w);
    d.emplace_back(w, w, w, w, 1);
  }
  LinkCutTree<Line, Ass, hoge> T(d);
  int s, e;
  for (int i = 1; i < n; ++i) {
    scanf("%d %d", &s, &e);
    T.link(s - 1, e - 1);
  }
  int t, a, b;
  Ass c(0);
  while (q--) {
    scanf("%d %d %d %d", &t, &a, &b, &c.a);
    if (t == 1)
      T.update(a - 1, b - 1, c);
    else
      printf("%d\\n", T.path(a - 1, b - 1).max);
  }
  return 0;
}