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

#include <algorithm>
#include <climits>
#include <iostream>
#include <utility>
#include <vector>
using namespace std;

class RMQsub1 {                         // 隣接差が±1だけのRMQ
  std::vector<int> pattern;             // ブロックがどのパターンか
  std::vector<std::vector<int>> minpos; // バイナリパターンに対する最小位置
  std::vector<int> dat;                 // 葉でないノード
  std::vector<int> depth;
  int blocksize;
  int n;
  int query(int a, int b, int k, int l, int r) const {
    if (r <= a || b <= l)
      return -1;
    if (n - 1 <= k) { // leaf
      if (pattern[k - (n - 1)] == -1)
        return -1;
      int s = l < a ? a % blocksize : 0;
      int t = r <= b ? blocksize : b % blocksize;
      return (k - (n - 1)) * blocksize +
             minpos[pattern[k - (n - 1)]][s * blocksize + t - 1];
    } else {
      if (a <= l && r <= b)
        return dat[k];
      int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
      int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
      if (vl == -1)
        return vr;
      return vr == -1 || depth[vl] < depth[vr] ? vl : vr;
    }
  }

public:
  RMQsub1() {}
  void build(std::vector<int> &a) {
    depth = a;
    int n = a.size();
    int k = 1;
    while ((1 << k) < a.size())
      k++;
    blocksize = k - 1; // log(n)/2
    if (blocksize == 0)
      blocksize = 1;
    int m = (n + blocksize - 1) / blocksize; // num node
    while (m & m - 1)
      m += m & -m;
    this->n = m;
    dat.resize(m - 1, -1);
    pattern.resize(n, -1);
    minpos.resize(1 << blocksize - 1);
    for (int i = 0; i < (n + blocksize - 1) / blocksize; i++) {
      int s = i * blocksize;
      int p = 0;
      for (int j = 1; j < blocksize && s + j < n; j++) {
        if (a[s + j - 1] > a[s + j])
          p |= 1 << j - 1;
      }
      pattern[i] = p;
      int b = (i + 1) * blocksize <= n ? blocksize : n - i * blocksize;
      if (minpos[p].empty()) {
        minpos[p].resize(blocksize * blocksize);
        for (int j = 0; j < blocksize; j++) {
          int d = 0, pos = j, mind = 0;
          minpos[p][j * blocksize + j] = pos;
          for (int k = j + 1; k < blocksize; k++) {
            if (p >> k - 1 & 1)
              d--;
            else
              d++;
            if (d < mind) {
              mind = d;
              pos = k;
            }
            minpos[p][j * blocksize + k] = pos;
          }
        }
      }
      if (m == 1)
        break;
      int par = (m - 1 + i - 1) / 2;
      if (dat[par] == -1 ||
          a[i * blocksize + minpos[p][0 + b - 1]] < a[dat[par]])
        dat[par] = i * blocksize + minpos[p][0 + b - 1];
    }
    dat.resize(m - 1);
    for (int i = (m - 2) / 2 - 1; i >= 0; i--) {
      int vl, vr;
      vl = dat[2 * i + 1];
      vr = dat[2 * i + 2];
      dat[i] = vr == -1 || a[vl] < a[vr] ? vl : vr;
    }
  }
  int query(int a, int b) const { //[a,b)の最小値
    return query(a, b, 0, 0, n * blocksize);
  }
};

class LCA {
  vector<int> eulertour;
  vector<int> vertex;
  // SparseTableRMQ rmq;
  // RMQ rmq;
  RMQsub1 rmq;
  void dfs(const vector<int> edge[], int n, vector<int> &depth, int d, int u) {
    eulertour[u] = vertex.size();
    vertex.push_back(u);
    depth.push_back(d);
    for (int i = 0; i < edge[u].size(); i++) {
      dfs(edge, n, depth, d + 1, edge[u][i]);
      vertex.push_back(u);
      depth.push_back(d);
    }
  }

public:
  LCA(const vector<int> edge[], int n, int root) : eulertour(n) {
    vector<int> depth;
    dfs(edge, n, depth, 1, root);
    vertex.push_back(root);
    depth.push_back(0);
    rmq.build(depth);
  }
  int query(int u, int v) const {
    if (u == v)
      return u;
    if (eulertour[u] > eulertour[v])
      swap(u, v);
    return vertex[rmq.query(eulertour[u], eulertour[v])];
  }
};

vector<int> edge[100000];
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n;
  cin >> n;
  for (int i = 0; i < n; i++) {
    int k, v;
    cin >> k;
    for (int j = 0; j < k; j++) {
      cin >> v;
      edge[i].push_back(v);
    }
  }
  LCA lca(edge, n, 0);
  int q, u, v;
  cin >> q;
  for (int i = 0; i < q; i++) {
    cin >> u >> v;
    cout << lca.query(u, v) << endl;
  }
  return 0;
}

Error: 0

Fixed submission:

#include <algorithm>
#include <climits>
#include <iostream>
#include <utility>
#include <vector>
using namespace std;

class RMQsub1 {                         // 隣接差が±1だけのRMQ
  std::vector<int> pattern;             // ブロックがどのパターンか
  std::vector<std::vector<int>> minpos; // バイナリパターンに対する最小位置
  std::vector<int> dat;                 // 葉でないノード
  std::vector<int> depth;
  int blocksize;
  int n;
  int query(int a, int b, int k, int l, int r) const {
    if (r <= a || b <= l)
      return -1;
    if (n - 1 <= k) { // leaf
      if (pattern[k - (n - 1)] == -1)
        return -1;
      int s = l < a ? a % blocksize : 0;
      int t = r <= b ? blocksize : b % blocksize;
      return (k - (n - 1)) * blocksize +
             minpos[pattern[k - (n - 1)]][s * blocksize + t - 1];
    } else {
      if (a <= l && r <= b)
        return dat[k];
      int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
      int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
      if (vl == -1)
        return vr;
      return vr == -1 || depth[vl] < depth[vr] ? vl : vr;
    }
  }

public:
  RMQsub1() {}
  void build(std::vector<int> &a) {
    depth = a;
    int n = a.size();
    int k = 1;
    while ((1 << k) < a.size())
      k++;
    blocksize = k - 1;                       // log(n)/2
    int m = (n + blocksize - 1) / blocksize; // num node
    while (m & m - 1)
      m += m & -m;
    this->n = m;
    dat.resize(m - 1, -1);
    pattern.resize(n, -1);
    minpos.resize(1 << blocksize - 1);
    for (int i = 0; i < (n + blocksize - 1) / blocksize; i++) {
      int s = i * blocksize;
      int p = 0;
      for (int j = 1; j < blocksize && s + j < n; j++) {
        if (a[s + j - 1] > a[s + j])
          p |= 1 << j - 1;
      }
      pattern[i] = p;
      int b = (i + 1) * blocksize <= n ? blocksize : n - i * blocksize;
      if (minpos[p].empty()) {
        minpos[p].resize(blocksize * blocksize);
        for (int j = 0; j < blocksize; j++) {
          int d = 0, pos = j, mind = 0;
          minpos[p][j * blocksize + j] = pos;
          for (int k = j + 1; k < blocksize; k++) {
            if (p >> k - 1 & 1)
              d--;
            else
              d++;
            if (d < mind) {
              mind = d;
              pos = k;
            }
            minpos[p][j * blocksize + k] = pos;
          }
        }
      }
      int par = (m - 1 + i - 1) / 2;
      if (dat[par] == -1 ||
          a[i * blocksize + minpos[p][0 + b - 1]] < a[dat[par]])
        dat[par] = i * blocksize + minpos[p][0 + b - 1];
    }
    dat.resize(m - 1);
    for (int i = (m - 2) / 2 - 1; i >= 0; i--) {
      int vl, vr;
      vl = dat[2 * i + 1];
      vr = dat[2 * i + 2];
      dat[i] = vr == -1 || a[vl] < a[vr] ? vl : vr;
    }
  }
  int query(int a, int b) const { //[a,b)の最小値
    return query(a, b, 0, 0, n * blocksize);
  }
};

class LCA {
  vector<int> eulertour;
  vector<int> vertex;
  // SparseTableRMQ rmq;
  // RMQ rmq;
  RMQsub1 rmq;
  void dfs(const vector<int> edge[], int n, vector<int> &depth, int d, int u) {
    eulertour[u] = vertex.size();
    vertex.push_back(u);
    depth.push_back(d);
    for (int i = 0; i < edge[u].size(); i++) {
      dfs(edge, n, depth, d + 1, edge[u][i]);
      vertex.push_back(u);
      depth.push_back(d);
    }
  }

public:
  LCA(const vector<int> edge[], int n, int root) : eulertour(n) {
    vector<int> depth;
    dfs(edge, n, depth, 1, root);
    vertex.push_back(root);
    depth.push_back(0);
    rmq.build(depth);
  }
  int query(int u, int v) const {
    if (u == v)
      return u;
    if (eulertour[u] > eulertour[v])
      swap(u, v);
    return vertex[rmq.query(eulertour[u], eulertour[v])];
  }
};

vector<int> edge[100000];
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n;
  cin >> n;
  for (int i = 0; i < n; i++) {
    int k, v;
    cin >> k;
    for (int j = 0; j < k; j++) {
      cin >> v;
      edge[i].push_back(v);
    }
  }
  LCA lca(edge, n, 0);
  int q, u, v;
  cin >> q;
  for (int i = 0; i < q; i++) {
    cin >> u >> v;
    cout << lca.query(u, v) << endl;
  }
  return 0;
}