Problem p01756 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct SuffixArray {
  string s;
  vector<int> sa;

  SuffixArray(const string &S) {
    s = S;
    int n = S.length();
    sa.assign(n + 1, 0);
    vector<int> rnk(n + 1), tmp(n + 1);
    for (int i = 0; i <= n; i++) {
      sa[i] = i;
      rnk[i] = i < n ? S[i] : -1;
    }
    int k = 0;
    auto compare_sa = [&](int i, int j) {
      if (rnk[i] != rnk[j])
        return rnk[i] < rnk[j];
      else {
        int ri = i + k <= n ? rnk[i + k] : -1;
        int rj = j + k <= n ? rnk[j + k] : -1;
        return ri < rj;
      }
    };
    for (k = 1; k <= n; k *= 2) {
      sort(sa.begin(), sa.end(), compare_sa);
      tmp[sa[0]] = 0;
      for (int i = 1; i <= n; i++) {
        tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
      }
      for (int i = 0; i <= n; i++) {
        rnk[i] = tmp[i];
      }
    }
  }

  bool contain(const string &T) {
    int a = 0, b = s.size();
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (s.compare(sa[c], T.length(), T) < 0)
        a = c;
      else
        b = c;
    }
    return s.compare(sa[b], T.length(), T) == 0;
  }

  int lower_bound(const string &T) {
    int a = 0, b = s.size();
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (s.compare(sa[c], T.length(), T) < 0)
        a = c;
      else
        b = c;
    }
    return b;
  }

  int upper_bound(const string &T) {
    int a = 0, b = s.size() + 1;
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (s.compare(sa[c], T.length(), T) <= 0)
        a = c;
      else
        b = c;
    }
    return b;
  }

  int get(int idx) { return sa[idx]; }
};

const int MAX_N = 1 << 17;
const int INF = 1 << 25;

class MinSegTree {
  int n, dat[2 * MAX_N - 1];

public:
  void init(int n_) {
    n = 1;
    while (n < n_)
      n *= 2;
    for (int i = 0; i < 2 * n - 1; i++) {
      dat[i] = INF;
    }
  }

  void update(int k, int a) {
    k += n - 1;
    dat[k] = a;
    while (k > 0) {
      k = (k - 1) / 2;
      dat[k] = min(dat[k * 2 + 1], dat[k * 2 + 2]);
    }
  }

  int query(int a, int b) { return query(a, b, 0, 0, n); }

  int query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l)
      return INF;
    if (a <= l && r <= b)
      return dat[k];
    else {
      int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
      int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
      return min(vl, vr);
    }
  }

  void show() {
    for (int i = 0; i < n; i++) {
      cout << dat[i + n - 1] << " ";
    }
    cout << endl;
  }
};

MinSegTree min_seg;
MinSegTree min_segr;

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  string S, Sr;
  int m;
  cin >> S >> m;
  Sr = S;
  reverse(Sr.begin(), Sr.end());

  SuffixArray sa1(S), sa2(Sr);
  min_seg.init(S.size() + 1);
  min_segr.init(S.size() + 1);
  for (int i = 0; i < S.size() + 1; i++) {
    min_seg.update(i, sa1.get(i));
  }
  for (int i = 0; i < S.size() + 1; i++) {
    min_segr.update(i, sa2.get(i));
  }
  while (m--) {
    string x, y;
    cin >> x >> y;
    reverse(y.begin(), y.end());

    if (!sa1.contain(x) || !sa2.contain(y)) {
      cout << 0 << endl;
      continue;
    }

    int lb = sa1.lower_bound(x);
    int ub = sa1.upper_bound(x);
    int a = min_seg.query(lb, ub);
    lb = sa2.lower_bound(y);
    ub = sa2.upper_bound(y);
    int b = min_segr.query(lb, ub);
    if (a + x.size() <= S.size() - b && (S.size() - b) - y.size() + 1 >= a) {
      cout << S.size() - a - b << endl;
    } else {
      cout << 0 << endl;
    }
  }
}

Fixed submission:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct SuffixArray {
  string s;
  vector<int> sa;

  SuffixArray(const string &S) {
    s = S;
    int n = S.length();
    sa.assign(n + 1, 0);
    vector<int> rnk(n + 1), tmp(n + 1);
    for (int i = 0; i <= n; i++) {
      sa[i] = i;
      rnk[i] = i < n ? S[i] : -1;
    }
    int k = 0;
    auto compare_sa = [&](int i, int j) {
      if (rnk[i] != rnk[j])
        return rnk[i] < rnk[j];
      else {
        int ri = i + k <= n ? rnk[i + k] : -1;
        int rj = j + k <= n ? rnk[j + k] : -1;
        return ri < rj;
      }
    };
    for (k = 1; k <= n; k *= 2) {
      sort(sa.begin(), sa.end(), compare_sa);
      tmp[sa[0]] = 0;
      for (int i = 1; i <= n; i++) {
        tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
      }
      for (int i = 0; i <= n; i++) {
        rnk[i] = tmp[i];
      }
    }
  }

  bool contain(const string &T) {
    int a = 0, b = s.size();
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (s.compare(sa[c], T.length(), T) < 0)
        a = c;
      else
        b = c;
    }
    return s.compare(sa[b], T.length(), T) == 0;
  }

  int lower_bound(const string &T) {
    int a = 0, b = s.size();
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (s.compare(sa[c], T.length(), T) < 0)
        a = c;
      else
        b = c;
    }
    return b;
  }

  int upper_bound(const string &T) {
    int a = 0, b = s.size() + 1;
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (s.compare(sa[c], T.length(), T) <= 0)
        a = c;
      else
        b = c;
    }
    return b;
  }

  int get(int idx) { return sa[idx]; }
};

const int MAX_N = 1 << 20;
const int INF = 1 << 25;

class MinSegTree {
  int n, dat[2 * MAX_N - 1];

public:
  void init(int n_) {
    n = 1;
    while (n < n_)
      n *= 2;
    for (int i = 0; i < 2 * n - 1; i++) {
      dat[i] = INF;
    }
  }

  void update(int k, int a) {
    k += n - 1;
    dat[k] = a;
    while (k > 0) {
      k = (k - 1) / 2;
      dat[k] = min(dat[k * 2 + 1], dat[k * 2 + 2]);
    }
  }

  int query(int a, int b) { return query(a, b, 0, 0, n); }

  int query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l)
      return INF;
    if (a <= l && r <= b)
      return dat[k];
    else {
      int vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
      int vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
      return min(vl, vr);
    }
  }

  void show() {
    for (int i = 0; i < n; i++) {
      cout << dat[i + n - 1] << " ";
    }
    cout << endl;
  }
};

MinSegTree min_seg;
MinSegTree min_segr;

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  string S, Sr;
  int m;
  cin >> S >> m;
  Sr = S;
  reverse(Sr.begin(), Sr.end());

  SuffixArray sa1(S), sa2(Sr);
  min_seg.init(S.size() + 1);
  min_segr.init(S.size() + 1);
  for (int i = 0; i < S.size() + 1; i++) {
    min_seg.update(i, sa1.get(i));
  }
  for (int i = 0; i < S.size() + 1; i++) {
    min_segr.update(i, sa2.get(i));
  }
  while (m--) {
    string x, y;
    cin >> x >> y;
    reverse(y.begin(), y.end());

    if (!sa1.contain(x) || !sa2.contain(y)) {
      cout << 0 << endl;
      continue;
    }

    int lb = sa1.lower_bound(x);
    int ub = sa1.upper_bound(x);
    int a = min_seg.query(lb, ub);
    lb = sa2.lower_bound(y);
    ub = sa2.upper_bound(y);
    int b = min_segr.query(lb, ub);
    if (a + x.size() <= S.size() - b && (S.size() - b) - y.size() + 1 >= a) {
      cout << S.size() - a - b << endl;
    } else {
      cout << 0 << endl;
    }
  }
}