This documentation is automatically generated by online-judge-tools/verification-helper
#include "../incremental_matching.hpp"
#include <iostream>
using namespace std;
#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_D"
int main() {
cin.tie(nullptr), ios::sync_with_stdio(false);
IncrementalMatching<TrieNodeFL, c2i_0aA> trie(62);
string T, P;
int Q;
cin >> T >> Q;
while (Q--) cin >> P, trie.add(P);
for (auto n : trie.match(T)) cout << !!n << '\n';
}
#line 2 "data_structure/light_forward_list.hpp"
#include <vector>
// CUT begin
// Simple forward_list for MLE-sensitive situations
// Verify: <http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_D>
template <typename T> struct light_forward_list {
static std::vector<unsigned> ptr;
static std::vector<T> val;
unsigned head;
light_forward_list() : head(0) {}
void push_front(T x) {
ptr.push_back(head), val.push_back(x);
head = ptr.size() - 1;
}
struct iterator {
unsigned p;
iterator operator++() { return {p = ptr[p]}; }
T &operator*() { return val[p]; }
bool operator!=(const iterator &rhs) { return p != rhs.p; }
};
iterator begin() { return {head}; }
iterator end() { return {0}; }
};
template <typename T> std::vector<unsigned> light_forward_list<T>::ptr = {0};
template <typename T> std::vector<T> light_forward_list<T>::val = {T()};
#line 3 "string/incremental_matching.hpp"
#include <iostream>
#include <list>
#include <string>
#line 7 "string/incremental_matching.hpp"
// CUT begin
// [1] B. Meyer, "Incremental String Matching," Information Processing Letters, 21(5), 1985.
//
// (Dynamic version of Aho-Corasick algorithm)
// Overall complexity: O(K * (\sum_i |keyword_i|) * (\max_i |keyword_i|))
template <class T, int (*char2int)(char)> struct IncrementalMatching {
bool built;
const int D;
std::vector<T> node;
IncrementalMatching(int D_) : built(false), D(D_), node(1, D) {}
void enter_child(int n, int nn, int c) {
complete_failure(n, nn, c);
node[n].setch(c, nn);
int fnn = node[nn].fail;
node[fnn].inv_fail.push_back(nn);
complete_inverse(n, nn, c);
}
void complete_inverse(const int y, const int nn, const int c) {
for (auto it = node[y].inv_fail.begin();; it++) {
while (it != node[y].inv_fail.end() and node[*it].fail != y)
it = node[y].inv_fail.erase(it);
if (it == node[y].inv_fail.end()) return;
const int x = *it, xx = node[x].Goto(c);
if (xx) {
node[xx].fail = nn, node[nn].inv_fail.push_back(xx);
} else {
complete_inverse(x, nn, c);
}
}
}
std::vector<int> endpos;
int add(const std::string &keyword) { // Enter_in_tree() in [1]
built = false;
int n = 0;
for (const auto &cc : keyword) {
int c = char2int(cc), nn = node[n].Goto(c);
if (!nn) {
nn = node.size();
node.emplace_back(D), enter_child(n, nn, c);
}
n = nn;
}
return endpos.push_back(n), n;
}
void complete_failure(int n, int nn, int c) {
int m = n, Tmc = node[m].Goto(c);
while (m and !Tmc) m = node[m].fail, Tmc = node[m].Goto(c);
node[nn].fail = Tmc;
}
std::vector<int> visorder; // BFS order of node ids
void build() { // Build_failure() in [1]
built = true;
visorder = {0};
for (size_t p = 0; p < visorder.size(); p++) {
for (auto p : node[visorder[p]]) {
if (p.second) visorder.push_back(p.second);
}
}
}
int step(int now, int d) {
while (now and !node[now].Goto(d)) now = node[now].fail;
return node[now].Goto(d);
}
// Count occurences of each added keyword in `str`
std::vector<int> match(const std::string &str) {
if (!built) build();
std::vector<int> freq(node.size());
int now = 0;
for (const auto &c : str) freq[now = step(now, char2int(c))]++;
for (auto i = visorder.rbegin(); i != visorder.rend(); i++)
freq[node[*i].fail] += freq[*i];
std::vector<int> ret;
for (auto x : endpos) ret.push_back(freq[x]);
return ret;
}
};
struct TrieNodeFL {
static const int B = 8, mask = (1 << B) - 1;
light_forward_list<unsigned> chlist; // 下位 B bits が文字種,上位 bit が行き先
std::list<int> inv_fail;
int fail;
TrieNodeFL(int = 0) : fail(0) {}
int Goto(int c) {
for (const auto x : chlist) {
if ((x & mask) == c) return x >> B;
}
return 0;
}
void setch(int c, int i) { chlist.push_front(c + (i << B)); }
friend std::ostream &operator<<(std::ostream &os, TrieNodeFL &x) {
os << '[' << x.fail << '/';
for (const auto c : x.chlist) os << '(' << (c & mask) << ',' << (c >> B) << "),";
return os << ']';
}
struct iterator {
light_forward_list<unsigned>::iterator iter;
iterator operator++() { return {++iter}; }
std::pair<int, int> operator*() {
unsigned val = *iter;
return std::make_pair(val & mask, val >> B); // (char, next_pos)
}
bool operator!=(const iterator &rhs) { return iter != rhs.iter; }
};
iterator begin() { return {chlist.begin()}; }
iterator end() { return {chlist.end()}; }
};
int c2i_0aA(char c) { return isdigit(c) ? c - '0' : islower(c) ? c - 'a' + 10 : c - 'A' + 36; }
#line 3 "string/test/incremental_matching.test.cpp"
using namespace std;
#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_D"
int main() {
cin.tie(nullptr), ios::sync_with_stdio(false);
IncrementalMatching<TrieNodeFL, c2i_0aA> trie(62);
string T, P;
int Q;
cin >> T >> Q;
while (Q--) cin >> P, trie.add(P);
for (auto n : trie.match(T)) cout << !!n << '\n';
}