Problem p00998 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
template <typename T> constexpr T INF = numeric_limits<T>::max() / 10;
template <typename Monoid> struct AccRandomizedBinarySearchTree {
public:
  static constexpr int POOL_SIZE = 200000;

private:
  struct Node {
    using BaseMonoid = Monoid;
    using T = typename BaseMonoid::T;
    using Ptr = Node *;
    using PtrPair = pair<Ptr, Ptr>;
    Node() : left{}, right{}, value{}, accum{}, size{1} {}
    Node(const T &value)
        : left{}, right{}, value{value}, accum{value}, size{1} {}
    Ptr left, right;
    T value;
    T accum;
    int size;

    static void serialize(Ptr a, vector<T> &v) {
      if (a == nullptr) {
        return;
      } else {
        serialize(a->left, v);
        v.push_back(a->value);
        serialize(a->right, v);
      }
    }
    static unsigned xor128() {
      static unsigned x = 123456789;
      static unsigned y = 362436069;
      static unsigned z = 521288629;
      static unsigned w = 88675123;
      const unsigned t = x ^ (x << 11);
      x = y;
      y = z;
      z = w;
      return w = (w ^ (w << 19)) ^ (t ^ (t >> 8));
    }

    static unsigned getRand(const int maximum) { return xor128() % maximum; }

    static T acc(const T &a, const T &b) {
      static const BaseMonoid ACC{};
      return ACC(a, b);
    }

    static int getSize(const Ptr a) { return (a == nullptr) ? 0 : a->size; }
    static T getAcc(const Ptr a) {
      return (a == nullptr) ? BaseMonoid::identity() : a->accum;
    }

    static Ptr update(Ptr a) {
      a->size = getSize(a->left) + getSize(a->right) + 1;
      a->accum = acc(acc(getAcc(a->left), getAcc(a->right)), a->value);
      return a;
    }

    static Ptr merge(Ptr a, Ptr b) {
      if (a == nullptr) {
        return b;
      } else if (b == nullptr) {
        return a;
      }
      const int asize = getSize(a);
      const int bsize = getSize(b);
      if (getRand(asize + bsize) < asize) {
        a->right = merge(a->right, b);
        return update(a);
      } else {
        b->left = merge(a, b->left);
        return update(b);
      }
    }

    static PtrPair split(Ptr a, const int k) // size = (k,n-k)
    {
      if (a == nullptr) {
        return make_pair(Ptr{}, Ptr{});
      }
      if (k <= getSize(a->left)) {
        const PtrPair s = split(a->left, k);
        a->left = s.second;
        return make_pair(s.first, update(a));
      } else {
        const PtrPair s = split(a->right, k - getSize(a->left) - 1);
        a->right = s.first;
        return make_pair(update(a), s.second);
      }
    }
    static Ptr insert(Ptr a, const int k, Ptr b) {
      const PtrPair s = split(a, k);
      return merge(merge(s.first, b), s.second);
    }

    static PtrPair erase(Ptr a, const int k) {
      const PtrPair sr = split(a, k + 1);
      const PtrPair sl = split(sr.first, k);
      return make_pair(merge(sl.first, sr.second), update(sl.second));
    }
  };

  using Ptr = typename Node::Ptr;
  using PtrPair = typename Node::PtrPair;

  int head = 0;
  static Node pool[POOL_SIZE];
  Ptr alloc(const typename Node::T &x) {
    assert(head < POOL_SIZE);
    pool[head].value = x;
    pool[head].size = 1;
    pool[head].left = nullptr;
    pool[head].right = nullptr;
    pool[head].accum = x;
    head++;
    return pool + head - 1;
  }
  void garbage_collect() {
    vector<T> v;
    Node::serialize(root, v);
    head = 0;
    root = nullptr;
    rev_root = nullptr;
    for (int i = 0; i < v.size(); i++) {
      root = Node::insert(root, i, alloc(v[i]));
      if (use_reverse) {
        rev_root = Node::insert(rev_root, v.size() - i - 1, alloc(v[i]));
      }
    }
  }

  Ptr root;
  Ptr rev_root;
  const bool use_reverse;

public:
  using BaseMonoid = Monoid;
  using T = typename Node::T;
  AccRandomizedBinarySearchTree(const bool reversible = true)
      : root{}, rev_root{}, use_reverse{reversible} {}

  int getSize() const { return Node::getSize(root); }
  void insert(const int k, const T &value) {
    const int s = Node::getSize(root);
    assert(0 <= k);
    assert(k <= s);
    if (head == POOL_SIZE) {
      garbage_collect();
    }
    root = Node::insert(root, k, alloc(value));
    if (use_reverse) {
      rev_root = Node::insert(rev_root, s - k, alloc(value));
    }
  }
  void erase(const int k) {
    const int s = Node::getSize(root);
    assert(0 <= k);
    assert(k < s);
    Ptr p;
    tie(root, p) = Node::erase(root, k);
    if (p != nullptr) {
      p->left = Ptr{};
      p->right = Ptr{};
    }
    if (use_reverse) {
      tie(rev_root, p) = Node::erase(rev_root, s - k - 1);
      if (p != nullptr) {
        p->left = Ptr{};
        p->right = Ptr{};
      }
    }
  }
  T get(int k) const {
    assert(0 <= k);
    assert(k < Node::getSize(root));
    Ptr v = root;
    while (v != nullptr) {
      const int s = Node::getSize(v->left);
      if (s > k) {
        v = v->left;
      } else if (s == k) {
        return v->value;
      } else {
        v = v->right;
        k -= s + 1;
      }
    }
    return v->value;
  }

  void set(const int k, const T &value) {
    const int s = Node::getSize(root);
    assert(0 <= k);
    assert(k < s);
    const PtrPair sr = Node::split(root, k + 1);
    const PtrPair sl = Node::split(sr.first, k);
    const Ptr lr = sl.second;
    lr->value = value;
    lr->accum = value;
    root = Node::merge(Node::merge(sl.first, lr), sr.second);

    if (use_reverse) {
      const PtrPair rev_sr = Node::split(rev_root, s - k);
      const PtrPair rev_sl = Node::split(rev_sr.first, s - k - 1);
      const Ptr rev_lr = rev_sl.second;
      rev_lr->value = value;
      rev_lr->accum = value;
      rev_root = Node::merge(Node::merge(rev_sl.first, rev_lr), rev_sr.second);
    }
  }

  T accumulate(const int l, const int r) // [l,r)
  {
    assert(0 <= l);
    assert(l < r);
    assert(r <= Node::getSize(root));
    const PtrPair sr = Node::split(root, r);
    const PtrPair sl = Node::split(sr.first, l);
    const T ans = Node::getAcc(sl.second);
    root = Node::merge(Node::merge(sl.first, sl.second), sr.second);
    return ans;
  }
  void reverse(const int l, const int r) // [l,r)
  {
    assert(reverse);
    const int s = Node::getSize(root);
    assert(0 <= l);
    assert(l < r);
    assert(r <= s);
    const int width = r - l;
    if (width > 1) {
      const PtrPair sr = Node::split(root, r);
      const PtrPair sl = Node::split(sr.first, l);

      const PtrPair rev_sr = Node::split(rev_root, s - l);
      const PtrPair rev_sl = Node::split(rev_sr.first, s - r);

      root = Node::merge(Node::merge(sl.first, rev_sl.second), sr.second);
      rev_root =
          Node::merge(Node::merge(rev_sl.first, sl.second), rev_sr.second);
    }
  }

  void shiftRight(const int l, const int r, const int count) // [l,r)
  {
    const int s = Node::getSize(root);
    assert(0 <= l);
    assert(l < r);
    assert(r <= s);
    const int width = r - l;
    const int shift = count % width;

    if (shift > 0) {
      const PtrPair sr = Node::split(root, r);
      PtrPair sl = Node::split(sr.first, l);
      const PtrPair sm = Node::split(sl.second, width - shift);
      root = Node::merge(Node::merge(sl.first, sm.second),
                         Node::merge(sm.first, sr.second));
      if (use_reverse) {
        const PtrPair rev_sr = Node::split(rev_root, s - l);
        PtrPair rev_sl = Node::split(rev_sr.first, s - r);
        const PtrPair rev_sm = Node::split(rev_sl.second, shift);
        rev_root = Node::merge(Node::merge(rev_sl.first, rev_sm.second),
                               Node::merge(rev_sm.first, rev_sr.second));
      }
    }
  }

  void shiftLeft(const int l, const int r, const int count) // [l,r)
  {
    assert(0 <= l);
    assert(l < r);
    assert(r <= Node::getSize(root));
    const int width = r - l;
    const int shift = count % width;
    if (shift > 0) {
      shiftRight(l, r, width - shift);
    }
  }
};
template <typename T>
typename AccRandomizedBinarySearchTree<T>::Node AccRandomizedBinarySearchTree<
    T>::pool[AccRandomizedBinarySearchTree::POOL_SIZE];

template <typename T>
ostream &operator<<(ostream &os, const AccRandomizedBinarySearchTree<T> &rbst) {
  os << "[";
  for (int i = 0; i < rbst.getSize(); i++) {
    os << rbst.get(i) << ",";
  }
  os << "]" << endl;
  return os;
}

struct RBST_Monoid_Min {
  using T = int;
  T operator()(const T &a, const T &b) const { return min(a, b); }
  static constexpr T identity() { return INF<T>; }
};
using RBST = AccRandomizedBinarySearchTree<RBST_Monoid_Min>;

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int N, Q;
  cin >> N >> Q;
  RBST rbst;
  for (int i = 0; i < N; i++) {
    int a;
    cin >> a;
    rbst.insert(i, a);
  }
  for (int q = 0; q < Q; q++) {
    int x, y, z;
    cin >> x >> y >> z;
    if (x == 0) {
      rbst.shiftRight(y, z + 1, 1);
    } else if (x == 1) {
      cout << rbst.accumulate(y, z + 1) << "\n";
    } else {
      rbst.set(y, z);
    }
  }

  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;
template <typename T> constexpr T INF = numeric_limits<T>::max() / 10;
template <typename Monoid> struct AccRandomizedBinarySearchTree {
public:
  static constexpr int POOL_SIZE = 200000;

private:
  struct Node {
    using BaseMonoid = Monoid;
    using T = typename BaseMonoid::T;
    using Ptr = Node *;
    using PtrPair = pair<Ptr, Ptr>;
    Node() : left{}, right{}, value{}, accum{}, size{1} {}
    Node(const T &value)
        : left{}, right{}, value{value}, accum{value}, size{1} {}
    Ptr left, right;
    T value;
    T accum;
    int size;

    static void serialize(Ptr a, vector<T> &v) {
      if (a == nullptr) {
        return;
      } else {
        serialize(a->left, v);
        v.push_back(a->value);
        serialize(a->right, v);
      }
    }
    static unsigned xor128() {
      static unsigned x = 123456789;
      static unsigned y = 362436069;
      static unsigned z = 521288629;
      static unsigned w = 88675123;
      const unsigned t = x ^ (x << 11);
      x = y;
      y = z;
      z = w;
      return w = (w ^ (w << 19)) ^ (t ^ (t >> 8));
    }

    static unsigned getRand(const int maximum) { return xor128() % maximum; }

    static T acc(const T &a, const T &b) {
      static const BaseMonoid ACC{};
      return ACC(a, b);
    }

    static int getSize(const Ptr a) { return (a == nullptr) ? 0 : a->size; }
    static T getAcc(const Ptr a) {
      return (a == nullptr) ? BaseMonoid::identity() : a->accum;
    }

    static Ptr update(Ptr a) {
      a->size = getSize(a->left) + getSize(a->right) + 1;
      a->accum = acc(acc(getAcc(a->left), getAcc(a->right)), a->value);
      return a;
    }

    static Ptr merge(Ptr a, Ptr b) {
      if (a == nullptr) {
        return b;
      } else if (b == nullptr) {
        return a;
      }
      const int asize = getSize(a);
      const int bsize = getSize(b);
      if (getRand(asize + bsize) < asize) {
        a->right = merge(a->right, b);
        return update(a);
      } else {
        b->left = merge(a, b->left);
        return update(b);
      }
    }

    static PtrPair split(Ptr a, const int k) // size = (k,n-k)
    {
      if (a == nullptr) {
        return make_pair(Ptr{}, Ptr{});
      }
      if (k <= getSize(a->left)) {
        const PtrPair s = split(a->left, k);
        a->left = s.second;
        return make_pair(s.first, update(a));
      } else {
        const PtrPair s = split(a->right, k - getSize(a->left) - 1);
        a->right = s.first;
        return make_pair(update(a), s.second);
      }
    }
    static Ptr insert(Ptr a, const int k, Ptr b) {
      const PtrPair s = split(a, k);
      return merge(merge(s.first, b), s.second);
    }

    static PtrPair erase(Ptr a, const int k) {
      const PtrPair sr = split(a, k + 1);
      const PtrPair sl = split(sr.first, k);
      return make_pair(merge(sl.first, sr.second), update(sl.second));
    }
  };

  using Ptr = typename Node::Ptr;
  using PtrPair = typename Node::PtrPair;

  int head = 0;
  static Node pool[POOL_SIZE];
  Ptr alloc(const typename Node::T &x) {
    assert(head < POOL_SIZE);
    pool[head].value = x;
    pool[head].size = 1;
    pool[head].left = nullptr;
    pool[head].right = nullptr;
    pool[head].accum = x;
    head++;
    return pool + head - 1;
  }
  void garbage_collect() {
    vector<T> v;
    Node::serialize(root, v);
    head = 0;
    root = nullptr;
    rev_root = nullptr;
    for (int i = 0; i < v.size(); i++) {
      root = Node::insert(root, i, alloc(v[i]));
      if (use_reverse) {
        rev_root = Node::insert(rev_root, v.size() - i - 1, alloc(v[i]));
      }
    }
  }

  Ptr root;
  Ptr rev_root;
  const bool use_reverse;

public:
  using BaseMonoid = Monoid;
  using T = typename Node::T;
  AccRandomizedBinarySearchTree(const bool reversible = true)
      : root{}, rev_root{}, use_reverse{reversible} {}

  int getSize() const { return Node::getSize(root); }
  void insert(const int k, const T &value) {
    const int s = Node::getSize(root);
    assert(0 <= k);
    assert(k <= s);
    if (head == POOL_SIZE) {
      garbage_collect();
    }
    root = Node::insert(root, k, alloc(value));
    if (use_reverse) {
      rev_root = Node::insert(rev_root, s - k, alloc(value));
    }
  }
  void erase(const int k) {
    const int s = Node::getSize(root);
    assert(0 <= k);
    assert(k < s);
    Ptr p;
    tie(root, p) = Node::erase(root, k);
    if (p != nullptr) {
      p->left = Ptr{};
      p->right = Ptr{};
    }
    if (use_reverse) {
      tie(rev_root, p) = Node::erase(rev_root, s - k - 1);
      if (p != nullptr) {
        p->left = Ptr{};
        p->right = Ptr{};
      }
    }
  }
  T get(int k) const {
    assert(0 <= k);
    assert(k < Node::getSize(root));
    Ptr v = root;
    while (v != nullptr) {
      const int s = Node::getSize(v->left);
      if (s > k) {
        v = v->left;
      } else if (s == k) {
        return v->value;
      } else {
        v = v->right;
        k -= s + 1;
      }
    }
    return v->value;
  }

  void set(const int k, const T &value) {
    const int s = Node::getSize(root);
    assert(0 <= k);
    assert(k < s);
    const PtrPair sr = Node::split(root, k + 1);
    const PtrPair sl = Node::split(sr.first, k);
    const Ptr lr = sl.second;
    lr->value = value;
    lr->accum = value;
    root = Node::merge(Node::merge(sl.first, lr), sr.second);

    if (use_reverse) {
      const PtrPair rev_sr = Node::split(rev_root, s - k);
      const PtrPair rev_sl = Node::split(rev_sr.first, s - k - 1);
      const Ptr rev_lr = rev_sl.second;
      rev_lr->value = value;
      rev_lr->accum = value;
      rev_root = Node::merge(Node::merge(rev_sl.first, rev_lr), rev_sr.second);
    }
  }

  T accumulate(const int l, const int r) // [l,r)
  {
    assert(0 <= l);
    assert(l < r);
    assert(r <= Node::getSize(root));
    const PtrPair sr = Node::split(root, r);
    const PtrPair sl = Node::split(sr.first, l);
    const T ans = Node::getAcc(sl.second);
    root = Node::merge(Node::merge(sl.first, sl.second), sr.second);
    return ans;
  }
  void reverse(const int l, const int r) // [l,r)
  {
    assert(reverse);
    const int s = Node::getSize(root);
    assert(0 <= l);
    assert(l < r);
    assert(r <= s);
    const int width = r - l;
    if (width > 1) {
      const PtrPair sr = Node::split(root, r);
      const PtrPair sl = Node::split(sr.first, l);

      const PtrPair rev_sr = Node::split(rev_root, s - l);
      const PtrPair rev_sl = Node::split(rev_sr.first, s - r);

      root = Node::merge(Node::merge(sl.first, rev_sl.second), sr.second);
      rev_root =
          Node::merge(Node::merge(rev_sl.first, sl.second), rev_sr.second);
    }
  }

  void shiftRight(const int l, const int r, const int count) // [l,r)
  {
    const int s = Node::getSize(root);
    assert(0 <= l);
    assert(l < r);
    assert(r <= s);
    const int width = r - l;
    const int shift = count % width;

    if (shift > 0) {
      const PtrPair sr = Node::split(root, r);
      PtrPair sl = Node::split(sr.first, l);
      const PtrPair sm = Node::split(sl.second, width - shift);
      root = Node::merge(Node::merge(sl.first, sm.second),
                         Node::merge(sm.first, sr.second));
      if (use_reverse) {
        const PtrPair rev_sr = Node::split(rev_root, s - l);
        PtrPair rev_sl = Node::split(rev_sr.first, s - r);
        const PtrPair rev_sm = Node::split(rev_sl.second, shift);
        rev_root = Node::merge(Node::merge(rev_sl.first, rev_sm.second),
                               Node::merge(rev_sm.first, rev_sr.second));
      }
    }
  }

  void shiftLeft(const int l, const int r, const int count) // [l,r)
  {
    assert(0 <= l);
    assert(l < r);
    assert(r <= Node::getSize(root));
    const int width = r - l;
    const int shift = count % width;
    if (shift > 0) {
      shiftRight(l, r, width - shift);
    }
  }
};
template <typename T>
typename AccRandomizedBinarySearchTree<T>::Node AccRandomizedBinarySearchTree<
    T>::pool[AccRandomizedBinarySearchTree::POOL_SIZE];

template <typename T>
ostream &operator<<(ostream &os, const AccRandomizedBinarySearchTree<T> &rbst) {
  os << "[";
  for (int i = 0; i < rbst.getSize(); i++) {
    os << rbst.get(i) << ",";
  }
  os << "]" << endl;
  return os;
}

struct RBST_Monoid_Min {
  using T = int;
  T operator()(const T &a, const T &b) const { return min(a, b); }
  static constexpr T identity() { return INF<T>; }
};
using RBST = AccRandomizedBinarySearchTree<RBST_Monoid_Min>;

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int N, Q;
  cin >> N >> Q;
  RBST rbst(false);
  for (int i = 0; i < N; i++) {
    int a;
    cin >> a;
    rbst.insert(i, a);
  }
  for (int q = 0; q < Q; q++) {
    int x, y, z;
    cin >> x >> y >> z;
    if (x == 0) {
      rbst.shiftRight(y, z + 1, 1);
    } else if (x == 1) {
      cout << rbst.accumulate(y, z + 1) << "\n";
    } else {
      rbst.set(y, z);
    }
  }

  return 0;
}