Problem p01973 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 100005

enum Type {
  Unknown,
  TRUE,
  FALSE,
};

struct Node {
  int parent_id, children[26], suffix_link;
  bool finish_FLG;
  string pattern;
};

struct Info {
  Info(int arg_node_id, int arg_ch) {
    node_id = arg_node_id;
    ch = arg_ch;
  }

  int node_id, ch;
};

int index = 1, table[128];
char buf[NUM], P[NUM];
Node nodes[NUM];
Type memo[NUM];
map<string, int> MAP;

int main() {

  // ノードを数字化
  for (int i = 0; i < 26; i++) {
    table['a' + i] = i;
  }

  scanf("%s", buf);
  int length;
  for (length = 0; buf[length] != '\\0'; length++)
    ;

  // ★ルートの情報を設定★
  int root = 0;
  nodes[root].pattern = "";
  nodes[root].suffix_link = -1;

  // トライ木のノードを初期化
  for (int i = 0; i < NUM; i++) {
    nodes[i].parent_id = -1;
    nodes[i].finish_FLG = false;
    for (int k = 0; k < 26; k++) {
      nodes[i].children[k] = -1;
    }
  }

  int N;
  scanf("%d", &N);

  int tmp_ch, tmp_loc, parent_id, tmp_index;
  string tmp_pattern;

  bool FLG;

  MAP[""] = 0;

  // トライ木を構成する
  for (int loop = 0; loop < N; loop++) {

    scanf("%s", P);
    tmp_pattern.clear();

    tmp_index = 0;
    tmp_ch = table[P[tmp_index]];
    tmp_pattern += P[tmp_index];

    tmp_loc = root;
    tmp_index = 0;

    while (true) {

      parent_id = tmp_loc;
      FLG = false;

      if (nodes[tmp_loc].children[tmp_ch] == -1) {
        FLG = true;
        nodes[tmp_loc].children[tmp_ch] =
            index++; // ★新しいノードへ移動する場合★
      }
      // 子ノードに移動
      tmp_loc = nodes[tmp_loc].children[tmp_ch];

      if (FLG) {
        nodes[tmp_loc].parent_id = parent_id;
        nodes[tmp_loc].pattern = tmp_pattern;

        // MAPに登録
        MAP[tmp_pattern] = tmp_loc;
      }

      tmp_index++;

      if (P[tmp_index] == '\\0') { // 今回の数字が最後の文字だった場合
        nodes[tmp_loc].finish_FLG = true;
        break;
      }
      tmp_ch = table[P[tmp_index]];
      tmp_pattern += P[tmp_index];
    }
  }

  // Suffix_linkを構築する
  queue<Info> MAKE_SL;
  for (int i = 0; i < 26; i++) {
    if (nodes[root].children[i] != -1) {
      nodes[nodes[root].children[i]].suffix_link = root;
      MAKE_SL.push(Info(nodes[root].children[i],
                        i)); // ノードのidと、最後の経路をpushする
    }
  }
  int node_id;
  while (!MAKE_SL.empty()) {
    node_id = MAKE_SL.front().node_id; // ★新たにsuffix_linkを張りたいノードのid★
    tmp_ch = MAKE_SL.front().ch;
    MAKE_SL.pop();

    for (int i = 0; i < 26; i++) {
      if (nodes[node_id].children[i] != -1) {
        MAKE_SL.push(Info(nodes[node_id].children[i], i));
      }
    }

    // ★親のsuffix_link先は、自分のsuffix_link先のpre_fixになっているので、親のsuffix_link情報を利用する★

    // tmp_chへ下ることのできる、親からのsuffix_link先のノードを探す
    for (tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root;
         tmp_loc = nodes[tmp_loc].suffix_link) {
      if (nodes[tmp_loc].children[tmp_ch] != -1) {
        break;
      }
    }

    if (tmp_loc == root) {
      if (nodes[root].children[tmp_ch] != -1) {
        nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
      } else {
        nodes[node_id].suffix_link = root;
      }
    } else {
      nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
    }
  }

  // suffix_linkを辿り、finish_flgがtrueのものに出くわすか調べる
  for (int i = 0; i < index; i++) {
    memo[i] = Unknown;
  }

  queue<int> Q;
  for (int i = 0; i < 26; i++) {
    if (nodes[root].children[i] != -1) {
      Q.push(nodes[root].children[i]);
    }
  }

  // ノードに近いものから調べる
  while (!Q.empty()) {
    tmp_loc = Q.front();
    Q.pop();
    for (int i = 0; i < 26; i++) {
      if (nodes[tmp_loc].children[i] != -1) {
        Q.push(nodes[tmp_loc].children[i]);
      }
    }

    if (nodes[tmp_loc].finish_FLG) {
      memo[tmp_loc] = TRUE;
    } else {
      for (int k = nodes[tmp_loc].suffix_link; k != root;
           k = nodes[k].suffix_link) {
        if (memo[k] != Unknown) {
          memo[tmp_loc] = memo[k];
          break;
        }
        if (nodes[k].finish_FLG) {
          memo[tmp_loc] = TRUE;
          break;
        }
      }
      if (memo[tmp_loc] == Unknown) {
        memo[tmp_loc] = FALSE;
      }
    }
  }

  int ans = 0;
  tmp_loc = root;

  for (int i = 0; i < length; i++) {
    tmp_ch = table[buf[i]];

    if (nodes[tmp_loc].children[tmp_ch] != -1) { // tmp_locから次に行ける場合
      tmp_loc = nodes[tmp_loc].children[tmp_ch];

      if (memo[tmp_loc] == TRUE) {
        ans++;
        tmp_loc = root;
      } else {
        // Do nothing
      }

    } else { // tmp_locから次へ行けない場合

      if (tmp_loc == root)
        continue; // rootの場合はSKIP

      // suffix_linkを辿り、tmp_chへ移れるノードがあるか調べる
      for (tmp_loc = nodes[tmp_loc].suffix_link; tmp_loc != root;
           tmp_loc = nodes[tmp_loc].suffix_link) {
        if (nodes[tmp_loc].children[tmp_ch] != -1)
          break;
      }

      if (tmp_loc == root) { // rootまで戻った場合
        if (nodes[tmp_loc].children[tmp_ch] !=
            -1) { // rootの子にtmp_chがいる場合
          tmp_loc = nodes[tmp_loc].children[tmp_ch];
          if (nodes[tmp_loc].finish_FLG) {
            ans++;
            tmp_loc = root;
          }
        } else {
          // Do nothing
        }
      } else { // 途中でtmp_chへ移れるノードが見つかった場合
        tmp_loc = nodes[tmp_loc].children[tmp_ch];

        if (memo[tmp_loc] == TRUE) {
          ans++;
          tmp_loc = root;
        } else {
          // Do nothing
        }
      }
    }
  }

  printf("%d\\n", ans);

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 100005

enum Type {
  Unknown,
  TRUE,
  FALSE,
};

struct Node {
  int parent_id, length, children[26], suffix_link;
  bool finish_FLG;
  vector<int> pattern_index;
  string pattern;
};

struct Info {
  Info(string arg_parent, string arg_line) {
    parent = arg_parent;
    line = arg_line;
  }

  string parent, line;
};

int index = 1, table[128], p_length[NUM];
char buf[NUM], P[NUM];
Node nodes[NUM];
Type memo[NUM];
map<string, int> MAP;
map<int, int> LENGTH_MAP;

int main() {

  // ノードを数字化
  for (int i = 0; i < 26; i++) {
    table['a' + i] = i;
  }

  scanf("%s", buf);
  int length;
  for (length = 0; buf[length] != '\\0'; length++)
    ;

  // ★ルートの情報を設定★
  int root = 0;
  nodes[root].pattern = "";

  // トライ木のノードを初期化
  for (int i = 0; i < NUM; i++) {
    nodes[i].parent_id = -1;
    nodes[i].finish_FLG = false;
    nodes[i].suffix_link = root; // siffx_link先はとりあえずrootにしておく
    for (int k = 0; k < 26; k++) {
      nodes[i].children[k] = -1;
    }
  }

  int N;
  scanf("%d", &N);

  int tmp_ch, tmp_loc, parent_id, tmp_index;
  string tmp_pattern;

  bool FLG;

  MAP[""] = 0;

  vector<int> LENGTH;

  // トライ木を構成する
  for (int loop = 0; loop < N; loop++) {

    scanf("%s", P);
    tmp_pattern.clear();

    tmp_index = 0;
    tmp_ch = table[P[tmp_index]];
    tmp_pattern += P[tmp_index];

    tmp_loc = root;
    tmp_index = 0;

    while (true) {

      parent_id = tmp_loc;
      FLG = false;

      if (nodes[tmp_loc].children[tmp_ch] == -1) {
        FLG = true;
        nodes[tmp_loc].children[tmp_ch] =
            index++; // ★新しいノードへ移動する場合★
      }
      // 子ノードに移動
      tmp_loc = nodes[tmp_loc].children[tmp_ch];

      nodes[tmp_loc].pattern_index.push_back(loop);

      if (FLG) {
        nodes[tmp_loc].parent_id = parent_id;
        nodes[tmp_loc].pattern = tmp_pattern;
        nodes[tmp_loc].length = tmp_index;

        // MAPに登録
        MAP[tmp_pattern] = tmp_loc;
      }

      tmp_index++;

      if (P[tmp_index] == '\\0') { // 今回の数字が最後の文字だった場合
        nodes[tmp_loc].finish_FLG = true;
        p_length[loop] = tmp_index;
        LENGTH.push_back(tmp_index);
        break;
      }
      tmp_ch = table[P[tmp_index]];
      tmp_pattern += P[tmp_index];
    }
  }

  sort(LENGTH.begin(), LENGTH.end());
  LENGTH.erase(unique(LENGTH.begin(), LENGTH.end()), LENGTH.end());

  for (int i = 0; i < LENGTH.size(); i++) {
    LENGTH_MAP[LENGTH[i]] = i; // 文字長と、何番目かの対応を記録
  }

  int substr_length, max_pattern_len, max_loc;

  // Suffix_linkを構築する
  for (int i = 1; i < index; i++) {

    substr_length = nodes[i].length - 1;

    max_pattern_len = 0;
    // そのノード上にある文字はあるパターンの部分文字列なので、属するパターンの最大長を求める
    for (int k = 0; k < nodes[i].pattern_index.size(); k++) {
      max_pattern_len =
          max(max_pattern_len, p_length[nodes[i].pattern_index[k]]);
    }

    max_loc = LENGTH_MAP[max_pattern_len];

    if (max_loc > 0) {
      substr_length = min(substr_length, LENGTH[max_loc - 1]);
    }

    // 1文字ずつ先頭から文字を削っていって、一致するところでsuffix_link(最大一致接尾辞へのリンク)を張る
    int cut = 1;
    while (cut <= substr_length) {
      tmp_pattern = nodes[i].pattern.substr(cut);
      auto at = MAP.find(tmp_pattern);
      if (at != MAP.end()) {
        nodes[i].suffix_link = MAP[tmp_pattern];
        break;
      }
      cut++;
    }
    // suffix_linkが見つからなかった場合でも、元々rootにsuffix_linkを張ってあるので操作は不要
  }

  // suffix_linkを辿り、finish_flgがtrueのものに出くわすか調べる
  for (int i = 0; i < index; i++) {
    memo[i] = Unknown;
  }

  queue<int> Q;
  for (int i = 0; i < 26; i++) {
    if (nodes[root].children[i] != -1) {
      Q.push(nodes[root].children[i]);
    }
  }

  // ノードに近いものから調べる
  while (!Q.empty()) {
    tmp_loc = Q.front();
    Q.pop();
    for (int i = 0; i < 26; i++) {
      if (nodes[tmp_loc].children[i] != -1) {
        Q.push(nodes[tmp_loc].children[i]);
      }
    }

    if (nodes[tmp_loc].finish_FLG) {
      memo[tmp_loc] = TRUE;
    } else {
      for (int k = nodes[tmp_loc].suffix_link; k != root;
           k = nodes[k].suffix_link) {
        if (memo[k] != Unknown) {
          memo[tmp_loc] = memo[k];
          break;
        }
        if (nodes[k].finish_FLG) {
          memo[tmp_loc] = TRUE;
          break;
        }
      }
      if (memo[tmp_loc] == Unknown) {
        memo[tmp_loc] = FALSE;
      }
    }
  }

  int ans = 0;
  tmp_loc = root;

  for (int i = 0; i < length; i++) {
    tmp_ch = table[buf[i]];

    if (nodes[tmp_loc].children[tmp_ch] != -1) { // tmp_locから次に行ける場合
      tmp_loc = nodes[tmp_loc].children[tmp_ch];

      if (memo[tmp_loc] == TRUE) {
        ans++;
        tmp_loc = root;
      } else {
        // Do nothing
      }

    } else { // tmp_locから次へ行けない場合

      if (tmp_loc == root)
        continue; // rootの場合はSKIP

      // suffix_linkを辿り、tmp_chへ移れるノードがあるか調べる
      for (tmp_loc = nodes[tmp_loc].suffix_link; tmp_loc != root;
           tmp_loc = nodes[tmp_loc].suffix_link) {
        if (nodes[tmp_loc].children[tmp_ch] != -1)
          break;
      }

      if (tmp_loc == root) { // rootまで戻った場合
        if (nodes[tmp_loc].children[tmp_ch] !=
            -1) { // rootの子にtmp_chがいる場合
          tmp_loc = nodes[tmp_loc].children[tmp_ch];
          if (nodes[tmp_loc].finish_FLG) {
            ans++;
            tmp_loc = root;
          }
        } else {
          // Do nothing
        }
      } else { // 途中でtmp_chへ移れるノードが見つかった場合
        tmp_loc = nodes[tmp_loc].children[tmp_ch];

        if (memo[tmp_loc] == TRUE) {
          ans++;
          tmp_loc = root;
        } else {
          // Do nothing
        }
      }
    }
  }

  printf("%d\\n", ans);

  return 0;
}