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

#include <bits/stdc++.h>
#define range(i, a, b) for (int i = (a); i < (b); i++)
#define rep(i, b) for (int i = 0; i < (b); i++)
#define all(a) (a).begin(), (a).end()
#define show(x) cerr << #x << " = " << (x) << endl;
// const int INF = 1e8;
using namespace std;

class SuffixArray {
private:
  int n;
  vector<int> rank;

public:
  string s;
  vector<int> idx;
  SuffixArray(string &s)
      : n(s.size()), rank(s.size() + 1), s(s), idx(s.size() + 1) {
    rep(i, n + 1) {
      idx[i] = i;
      rank[i] = i < n ? s[i] : -1;
    }

    int k;
    auto comp = [&](const int i, const int j) -> bool {
      if (rank[i] != rank[j])
        return rank[i] < rank[j];
      else {
        int ri = i + k <= n ? rank[i + k] : -1;
        int rj = j + k <= n ? rank[j + k] : -1;
        return ri < rj;
      }
    };

    vector<int> tmp(n + 1);
    for (k = 1; k <= n; k *= 2) {
      sort(all(idx), comp);

      tmp[idx[0]] = 0;
      range(i, 1, n + 1) {
        tmp[idx[i]] = tmp[idx[i - 1]] + (comp(idx[i - 1], idx[i]) ? 1 : 0);
      }
      rank = tmp;
    }
  }
  bool contain(string &t) {
    int right = n, left = 0;
    while (right - left > 1) {
      int mid = (right + left) / 2;
      if (s.substr(idx[mid], t.size()) < t)
        left = mid;
      else
        right = mid;
    }
    return s.substr(idx[right], t.size()) == t;
  }
};

int main() {
  string s;
  int n;
  cin >> s >> n;

  SuffixArray suf(s);
  rep(i, n) {
    string a;
    cin >> a;
    cout << suf.contain(a) << endl;
  }
}


Error: 0

Fixed submission:

#include <bits/stdc++.h>
#define range(i, a, b) for (int i = (a); i < (b); i++)
#define rep(i, b) for (int i = 0; i < (b); i++)
#define all(a) (a).begin(), (a).end()
#define show(x) cerr << #x << " = " << (x) << endl;
// const int INF = 1e8;
using namespace std;

const int MAX = 30;

int encode(char c) {
  return 0 + c - 'a';

  assert(false && "invalid string");
}

struct Node {
  int nxt[MAX + 1];   // 次のalphabeteのノード番号
  int exist;          // 子ども以下に存在する文字列の数の合計
  vector<int> accept; // その文字列id
  Node() : exist(0) { memset(nxt, -1, sizeof(nxt)); }
};

class Trie {
private:
  void updateDirect(int node, int id) {
    ac.emplace_back(node);
    nodes[node].accept.emplace_back(id);
  }
  void updateChild(int node, int child, int id) { ++nodes[node].exist; }
  void add(const string &str, int str_index, int node_index, int id) {
    if (str_index == str.size())
      updateDirect(node_index, id);
    else {
      const int c = encode(str[str_index]);
      if (nodes[node_index].nxt[c] == -1) {
        nodes[node_index].nxt[c] = (int)nodes.size();
        nodes.emplace_back(Node());
      }
      add(str, str_index + 1, nodes[node_index].nxt[c], id);
      updateChild(node_index, nodes[node_index].nxt[c], id);
    }
  }
  void add(const string &str, int id) { add(str, 0, 0, id); }

public:
  vector<Node> nodes;
  vector<int> ac; // ac[i] := i番目のパターンを受理する状態番号
  int root;
  Trie() : root(0) { nodes.emplace_back(Node()); }
  void add(const string &str) { add(str, nodes[0].exist); }
  int size() { return (nodes[0].exist); }
  int nodesize() { return ((int)nodes.size()); }
};

class AhoCorasick : public Trie {
public:
  static const int FAIL = MAX;
  vector<int> correct;
  AhoCorasick() : Trie() {}

  void build() {
    correct.resize(nodes.size());
    rep(i, nodes.size()) correct[i] = (int)nodes[i].accept.size();

    queue<int> que;
    rep(i, MAX + 1) {
      if (~nodes[0].nxt[i]) {
        nodes[nodes[0].nxt[i]].nxt[FAIL] = 0;
        que.emplace(nodes[0].nxt[i]);
      } else
        nodes[0].nxt[i] = 0;
    }
    while (!que.empty()) {
      Node now = nodes[que.front()];
      correct[que.front()] += correct[now.nxt[FAIL]];
      que.pop();
      rep(i, MAX) {
        if (now.nxt[i] == -1)
          continue;
        int fail = now.nxt[FAIL];
        while (nodes[fail].nxt[i] == -1) {
          fail = nodes[fail].nxt[FAIL];
        }
        nodes[now.nxt[i]].nxt[FAIL] = nodes[fail].nxt[i];

        auto &u = nodes[now.nxt[i]].accept;
        auto &v = nodes[nodes[fail].nxt[i]].accept;
        vector<int> accept;
        set_union(all(u), all(v), back_inserter(accept));
        u = accept;
        que.emplace(now.nxt[i]);
      }
    }
  }
  // result := 各パターンがそれぞれ何度マッチしたか
  int match(const string &str, vector<int> &result, int now = 0) {
    result.assign(size(), 0);
    int count = 0;
    for (auto &c : str) {
      while (nodes[now].nxt[encode(c)] == -1)
        now = nodes[now].nxt[FAIL];
      now = nodes[now].nxt[encode(c)];
      count += correct[now];
      for (auto &v : nodes[now].accept)
        result[v]++;
    }
    return count;
  }
  int next(int now, char c) {
    while (nodes[now].nxt[encode(c)] == -1)
      now = nodes[now].nxt[FAIL];
    return nodes[now].nxt[encode(c)];
  }
};

int main() {
  string s;
  int n;
  cin >> s >> n;

  AhoCorasick aho;
  rep(i, n) {
    string a;
    cin >> a;
    aho.add(a);
  }
  vector<int> res;
  aho.build();
  aho.match(s, res);
  for (auto i : res)
    cout << (i == 0 ? 0 : 1) << endl;
}