Problem p02962 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
template <typename T> void fin(T const &t) {
  std::cout << t << std::endl;
  exit(0);
}

template <typename S>
void sa_is(S s, int B, std::vector<int> &sa, std::vector<int> &cnt) {
  int n = s.size();
  sa.resize(n + 1);
  if (n == 0)
    return;

  for (auto &c : s)
    ++c;
  s.push_back(0);
  ++B;

  std::vector<bool> iss(n + 1);
  std::vector<int> bin(B + 1), lms, is_lms(n + 1, -1);
  iss[n] = true;
  ++bin[1];
  for (int i = n - 1; i >= 0; --i) {
    iss[i] = (s[i] == s[i + 1]) ? iss[i + 1] : (s[i] < s[i + 1]);
    if (!iss[i] && iss[i + 1]) {
      is_lms[i + 1] = lms.size();
      lms.push_back(i + 1);
    }
    ++bin[s[i] + 1];
  }
  for (int i = 0; i < B; ++i)
    bin[i + 1] += bin[i];
  auto induce = [&](std::vector<int> const &lms) {
    sa.assign(n + 1, -1);
    cnt.assign(B, 0);
    for (auto x : lms)
      sa[bin[s[x] + 1] - ++cnt[s[x]]] = x;
    std::fill(cnt.begin(), cnt.end(), 0);
    for (auto x : sa)
      if (--x >= 0 && !iss[x]) {
        sa[bin[s[x]] + cnt[s[x]]++] = x;
      }
    std::fill(cnt.begin(), cnt.end(), 0);
    for (int i = n; i >= 0; --i) {
      int x = sa[i] - 1;
      if (x >= 0 && iss[x])
        sa[bin[s[x] + 1] - ++cnt[s[x]]] = x;
    }
  };
  induce(lms);
  int m = lms.size();
  if (m <= 1)
    return;
  std::vector<int> rec_lms;
  rec_lms.reserve(m);
  for (auto x : sa)
    if (is_lms[x] >= 0)
      rec_lms.push_back(x);
  int rec_n = 1;
  std::vector<int> rec_s(m);
  rec_s[m - 1 - is_lms[rec_lms[1]]] = rec_n;
  for (int i = 2; i < m; ++i) {
    int xl = rec_lms[i];
    int yl = rec_lms[i - 1];
    int xr = lms[is_lms[xl] - 1];
    int yr = lms[is_lms[yl] - 1];
    if (xr - xl != yr - yl)
      ++rec_n;
    else
      while (xl <= xr) {
        if (s[xl] != s[yl]) {
          ++rec_n;
          break;
        }
        ++xl;
        ++yl;
      }
    rec_s[m - 1 - is_lms[rec_lms[i]]] = rec_n;
  }
  sa_is(std::move(rec_s), rec_n + 1, sa, cnt);
  int li = m;
  for (int i = 1; i <= m; ++i) {
    rec_lms[--li] = lms[m - 1 - sa[i]];
  }
  induce(rec_lms);
}

template <typename S> struct suffix_array {
  int n_;
  std::vector<int> sa, rank, lcp, cnt;
  suffix_array(S s, int B) : n_(s.size()), rank(n_ + 1), lcp(n_) {
    sa_is(s, B, sa, cnt);
    for (int i = 0; i <= n_; ++i)
      rank[sa[i]] = i;
    int h = 0;
    lcp[0] = 0;
    for (int i = 0; i < n_; ++i) {
      int j = sa[rank[i] - 1];
      if (h > 0)
        --h;
      for (; i + h < n_ && j + h < n_; ++h)
        if (s[j + h] != s[i + h])
          break;
      lcp[rank[i] - 1] = h;
    }
  }
};

template <int MAXV> struct scc {
  std::vector<int> G[MAXV], rG[MAXV], vs;
  bool used[MAXV];
  // int cmp[MAXV];
  scc() {}
  void dfs(int v) {
    used[v] = true;
    for (auto c : G[v])
      if (!used[c])
        dfs(c);
    vs.push_back(v);
  }
  void rdfs(int v, int k) {
    used[v] = true;
    // cmp[v] = k;
    for (auto c : rG[v])
      if (!used[c])
        rdfs(c, k);
  }
  int build(int V) {
    std::fill_n(used, V, false);
    vs.clear();
    for (int v = 0; v < V; ++v)
      if (!used[v])
        dfs(v);
    std::fill_n(used, V, false);
    int k = 0;
    for (int i = vs.size() - 1; i >= 0; --i) {
      if (!used[vs[i]])
        rdfs(vs[i], k++);
    }
    return k;
  }
  void add_edge(int fr, int to) {
    G[fr].push_back(to);
    rG[to].push_back(fr);
  }
};

int const MAXN = 5e5;

scc<MAXN> sc;
int depth[MAXN];
int calc_depth(int v) {
  if (depth[v] >= 0)
    return depth[v];
  int res = -1;
  for (auto c : sc.G[v])
    res = std::max(res, calc_depth(c));
  ++res;
  return depth[v] = res;
}

int main() {
  std::string S, T;
  std::cin >> S >> T;
  int N = S.size(), M = T.size(), K = N + M - 1;
  std::vector<std::uint8_t> s2(K), t(M);
  for (int i = 0; i < N; ++i)
    s2[i] = S[i] - 'a';
  for (int i = N; i < K; ++i)
    s2[i] = s2[i - N];
  for (int i = 0; i < M; ++i)
    t[i] = T[i] - 'a';
  suffix_array<std::vector<std::uint8_t>> sa(s2, 26);

  int lb = std::partition_point(sa.sa.begin(), sa.sa.end(),
                                [&](auto &i) {
                                  for (int j = 0; j < M && j + i < K; ++j) {
                                    if (s2[i + j] != t[j])
                                      return s2[i + j] < t[j];
                                  }
                                  return K - i < M;
                                }) -
           sa.sa.begin();
  int ub = std::partition_point(sa.sa.begin(), sa.sa.end(),
                                [&](auto &i) {
                                  for (int j = 0; j < M && j + i < K; ++j) {
                                    if (s2[i + j] != t[j])
                                      return s2[i + j] < t[j];
                                  }
                                  return true;
                                }) -
           sa.sa.begin();
  std::vector<int> v;
  for (int i = lb; i < ub; ++i)
    if (sa.sa[i] < N)
      v.push_back(sa.sa[i]);

  if (v.size() < 1)
    fin(0);
  for (int x : v)
    sc.add_edge(x, (x + M) % N);
  if (sc.build(N) < N)
    fin(-1);
  std::fill_n(depth, N, -1);
  int ans = 0;
  for (int i = 0; i < N; ++i) {
    ans = std::max(ans, calc_depth(i));
  }
  fin(ans);

  return 0;
}


Fixed submission:
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
template <typename T> void fin(T const &t) {
  std::cout << t << std::endl;
  exit(0);
}

template <typename S>
void sa_is(S s, int B, std::vector<int> &sa, std::vector<int> &cnt) {
  int n = s.size();
  sa.resize(n + 1);
  if (n == 0)
    return;

  for (auto &c : s)
    ++c;
  s.push_back(0);
  ++B;

  std::vector<bool> iss(n + 1);
  std::vector<int> bin(B + 1), lms, is_lms(n + 1, -1);
  iss[n] = true;
  ++bin[1];
  for (int i = n - 1; i >= 0; --i) {
    iss[i] = (s[i] == s[i + 1]) ? iss[i + 1] : (s[i] < s[i + 1]);
    if (!iss[i] && iss[i + 1]) {
      is_lms[i + 1] = lms.size();
      lms.push_back(i + 1);
    }
    ++bin[s[i] + 1];
  }
  for (int i = 0; i < B; ++i)
    bin[i + 1] += bin[i];
  auto induce = [&](std::vector<int> const &lms) {
    sa.assign(n + 1, -1);
    cnt.assign(B, 0);
    for (auto x : lms)
      sa[bin[s[x] + 1] - ++cnt[s[x]]] = x;
    std::fill(cnt.begin(), cnt.end(), 0);
    for (auto x : sa)
      if (--x >= 0 && !iss[x]) {
        sa[bin[s[x]] + cnt[s[x]]++] = x;
      }
    std::fill(cnt.begin(), cnt.end(), 0);
    for (int i = n; i >= 0; --i) {
      int x = sa[i] - 1;
      if (x >= 0 && iss[x])
        sa[bin[s[x] + 1] - ++cnt[s[x]]] = x;
    }
  };
  induce(lms);
  int m = lms.size();
  if (m <= 1)
    return;
  std::vector<int> rec_lms;
  rec_lms.reserve(m);
  for (auto x : sa)
    if (is_lms[x] >= 0)
      rec_lms.push_back(x);
  int rec_n = 1;
  std::vector<int> rec_s(m);
  rec_s[m - 1 - is_lms[rec_lms[1]]] = rec_n;
  for (int i = 2; i < m; ++i) {
    int xl = rec_lms[i];
    int yl = rec_lms[i - 1];
    int xr = lms[is_lms[xl] - 1];
    int yr = lms[is_lms[yl] - 1];
    if (xr - xl != yr - yl)
      ++rec_n;
    else
      while (xl <= xr) {
        if (s[xl] != s[yl]) {
          ++rec_n;
          break;
        }
        ++xl;
        ++yl;
      }
    rec_s[m - 1 - is_lms[rec_lms[i]]] = rec_n;
  }
  sa_is(std::move(rec_s), rec_n + 1, sa, cnt);
  int li = m;
  for (int i = 1; i <= m; ++i) {
    rec_lms[--li] = lms[m - 1 - sa[i]];
  }
  induce(rec_lms);
}

template <typename S> struct suffix_array {
  int n_;
  std::vector<int> sa, rank, lcp, cnt;
  suffix_array(S s, int B) : n_(s.size()), rank(n_ + 1), lcp(n_) {
    sa_is(s, B, sa, cnt);
    for (int i = 0; i <= n_; ++i)
      rank[sa[i]] = i;
    int h = 0;
    lcp[0] = 0;
    for (int i = 0; i < n_; ++i) {
      int j = sa[rank[i] - 1];
      if (h > 0)
        --h;
      for (; i + h < n_ && j + h < n_; ++h)
        if (s[j + h] != s[i + h])
          break;
      lcp[rank[i] - 1] = h;
    }
  }
};

template <int MAXV> struct scc {
  std::vector<int> G[MAXV], rG[MAXV], vs;
  bool used[MAXV];
  // int cmp[MAXV];
  scc() {}
  void dfs(int v) {
    used[v] = true;
    for (auto c : G[v])
      if (!used[c])
        dfs(c);
    vs.push_back(v);
  }
  void rdfs(int v, int k) {
    used[v] = true;
    // cmp[v] = k;
    for (auto c : rG[v])
      if (!used[c])
        rdfs(c, k);
  }
  int build(int V) {
    std::fill_n(used, V, false);
    vs.clear();
    for (int v = 0; v < V; ++v)
      if (!used[v])
        dfs(v);
    std::fill_n(used, V, false);
    int k = 0;
    for (int i = vs.size() - 1; i >= 0; --i) {
      if (!used[vs[i]])
        rdfs(vs[i], k++);
    }
    return k;
  }
  void add_edge(int fr, int to) {
    G[fr].push_back(to);
    rG[to].push_back(fr);
  }
};

int const MAXN = 5e5;

scc<MAXN> sc;
int depth[MAXN];
int calc_depth(int v) {
  if (depth[v] >= 0)
    return depth[v];
  int res = -1;
  for (auto c : sc.G[v])
    res = std::max(res, calc_depth(c));
  ++res;
  return depth[v] = res;
}

int main() {
  std::string S, T;
  std::cin >> S >> T;
  int N = S.size(), M = T.size(), K = N + M - 1;
  std::vector<std::uint8_t> s2(K), t(M);
  for (int i = 0; i < N; ++i)
    s2[i] = S[i] - 'a';
  for (int i = N; i < K; ++i)
    s2[i] = s2[i - N];
  for (int i = 0; i < M; ++i)
    t[i] = T[i] - 'a';
  suffix_array<std::vector<std::uint8_t>> sa(s2, 26);

  int lb = std::partition_point(sa.sa.begin(), sa.sa.end(),
                                [&](auto &i) {
                                  for (int j = 0; j < M && j + i < K; ++j) {
                                    if (s2[i + j] != t[j])
                                      return s2[i + j] < t[j];
                                  }
                                  return K - i < M;
                                }) -
           sa.sa.begin();
  int ub = std::partition_point(sa.sa.begin(), sa.sa.end(),
                                [&](auto &i) {
                                  for (int j = 0; j < M && j + i < K; ++j) {
                                    if (s2[i + j] != t[j])
                                      return s2[i + j] < t[j];
                                  }
                                  return true;
                                }) -
           sa.sa.begin();
  std::vector<int> v;
  for (int i = lb; i < ub; ++i)
    if (sa.sa[i] < N)
      v.push_back(sa.sa[i]);

  if (v.size() < 1)
    fin(0);
  for (int fr : v) {
    int to = (fr + M) % N;
    if (fr == to)
      fin(-1);
    sc.add_edge(fr, to);
  }
  if (sc.build(N) < N)
    fin(-1);
  std::fill_n(depth, N, -1);
  int ans = 0;
  for (int i = 0; i < N; ++i) {
    ans = std::max(ans, calc_depth(i));
  }
  fin(ans);

  return 0;
}