6template <
int char_size>
18template <
int char_size,
int margin>
27 void update_direct(
int node,
int id) { nodes[node].accept.push_back(id); }
29 void update_child(
int node,
int child,
int id) { ++nodes[node].exist; }
31 void add(
const string& str,
int str_index,
int node_index,
int id) {
32 if (str_index == str.size()) {
35 const int c = str[str_index] - margin;
36 if (nodes[node_index].nxt[c] == -1) {
37 nodes[node_index].nxt[c] = (
int)nodes.size();
38 nodes.push_back(Node());
40 add(str, str_index + 1, nodes[node_index].nxt[c], id);
41 update_child(node_index, nodes[node_index].nxt[c], id);
45 void add(
const string& str,
int id) { add(str, 0, 0, id); }
48 void add(
const string& str) { add(str, nodes[0].exist); }
50 void query(
const string& str,
const function<
void(
int)>& f,
int str_index,
52 for (
auto& idx : nodes[node_index].accept) f(idx);
53 if (str_index == str.size()) {
56 const int c = str[str_index] - margin;
57 if (nodes[node_index].nxt[c] == -1)
return;
58 query(str, f, str_index + 1, nodes[node_index].nxt[c]);
63 void query(
const string& str,
const function<
void(
int)>& f) {
68 int count()
const {
return (nodes[0].exist); }
71 int size()
const {
return ((
int)nodes.size()); }
75template <
int char_size,
int margin>
77 using Trie<char_size + 1, margin>::
Trie;
79 const int FAIL = char_size;
84 correct.resize(
this->size());
85 for (
int i = 0; i <
this->size(); i++) {
86 correct[i] = (
int)
this->nodes[i].accept.size();
89 for (
int i = 0; i <= char_size; i++) {
90 if (~
this->nodes[0].nxt[i]) {
91 this->nodes[
this->nodes[0].nxt[i]].nxt[
FAIL] = 0;
92 que.emplace(
this->nodes[0].nxt[i]);
94 this->nodes[0].nxt[i] = 0;
97 while (!que.empty()) {
98 auto& now =
this->nodes[que.front()];
99 int fail = now.nxt[
FAIL];
100 correct[que.front()] += correct[fail];
102 for (
int i = 0; i < char_size; i++) {
104 this->nodes[now.nxt[i]].nxt[
FAIL] =
this->nodes[fail].nxt[i];
106 auto& u =
this->nodes[now.nxt[i]].accept;
107 auto& v =
this->nodes[
this->nodes[fail].nxt[i]].accept;
109 set_union(begin(u), end(u), begin(v), end(v),
110 back_inserter(accept));
113 que.emplace(now.nxt[i]);
115 now.nxt[i] =
this->nodes[fail].nxt[i];
123 unordered_map<
int,
int> result, visit_cnt;
124 for (
auto& c : str) {
125 now =
this->nodes[now].nxt[c - margin];
128 for (
auto& [now, cnt] : visit_cnt) {
129 for (
auto& v :
this->nodes[now].accept) result[v] += cnt;
136 now =
this->nodes[now].nxt[c - margin];
137 return {correct[now], now};
143 for (
auto& c : str) {
144 auto nxt = move(c, now);
void build(bool heavy=true)
前計算 オートマトンを構築する
pair< int64_t, int > move(const char &c, int now=0)
現在のノード now から文字 c で遷移したときの(見つかったパターンの総数, 次のノード)を返す
unordered_map< int, int > match(const string &str, int now=0)
str の中に出現する全パターンの出現回数を返す
pair< int64_t, int > move(const string &str, int now=0)
str に対して move を適用する。(見つかったパターンの総数, 最終ノードを返す)
void update_direct(int node, int id)
void query(const string &str, const function< void(int)> &f)
strをprefixとして持つ全ての文字列に対し、見つかった文字列のインデックスそれぞれに対してfを実行する
void add(const string &str, int str_index, int node_index, int id)
void add(const string &str)
文字列 str を追加する
void add(const string &str, int id)
void query(const string &str, const function< void(int)> &f, int str_index, int node_index)
void update_child(int node, int child, int id)
int exist
このノードをprefixとして持つ文字列の個数
vector< int > accept
このノードが終点である文字列の個数
int nxt[char_size]
子どものノードのインデクス, ないなら-1