|
1 | 1 | #pragma once |
2 | | -#include <iostream> |
3 | | -#include <list> |
4 | | -#include <memory> |
| 2 | +#include <algorithm> |
5 | 3 | #include <queue> |
6 | 4 | #include <stack> |
7 | 5 | #include <string> |
8 | | -#include <unordered_map> |
9 | 6 | #include <vector> |
10 | 7 |
|
11 | 8 | namespace mtd { |
12 | | - auto nullLambda = [](int, const std::list<int>&) {}; |
13 | 9 | class PalindromicTree { |
14 | | - // static constexpr auto nullLambda = [](int, const std::list<int>&) {};// |
15 | | - // c++17 |
16 | | - |
17 | | - class Node : public std::enable_shared_from_this<Node> { |
18 | | - // 回文の右端itr |
19 | | - std::list<int> m_itrs; |
20 | | - // 回文サイズ |
21 | | - const int m_size; |
22 | | - |
23 | | - // 最大の回文接尾辞 |
24 | | - std::weak_ptr<Node> m_suffixLink; |
25 | | - // 次サイズの回文(囲む文字, 次のNode) |
26 | | - std::unordered_map<char, std::shared_ptr<Node>> m_edges; |
27 | | - |
28 | | - // xAxとなるAを探す(x=str[itr]) |
29 | | - auto find(int itr, const std::string& s) { |
30 | | - auto p = this->weak_from_this(); |
31 | | - while (true) { |
32 | | - auto size = p.lock()->m_size; |
33 | | - // rootにたどり着いた |
34 | | - if (size == -1) { return p; } |
35 | | - // 現在地"A"において"xAx"となる |
36 | | - if (itr - size - 1 >= 0 && s[itr] == s[itr - size - 1]) { return p; } |
37 | | - p = p.lock()->m_suffixLink; |
| 10 | + struct Node { |
| 11 | + int size; |
| 12 | + int suffix_link; |
| 13 | + int first_itr = -1; |
| 14 | + std::vector<std::pair<char, int>> edges; |
| 15 | + std::vector<int> rest_itrs; |
| 16 | + |
| 17 | + Node(int s, int sl) : size(s), suffix_link(sl) {} |
| 18 | + |
| 19 | + auto find_edge(char c) const -> int { |
| 20 | + for (const auto& [ch, idx] : edges) { |
| 21 | + if (ch == c) { return idx; } |
38 | 22 | } |
| 23 | + return -1; |
39 | 24 | } |
40 | 25 |
|
41 | | - // 新しい回文Nodeを作成する |
42 | | - auto create(int itr, const std::string& s) { |
43 | | - // suffixLinkの探索 |
44 | | - auto suffixLinkFrom = |
45 | | - m_suffixLink.lock() /*->m_suffixLink.lock()*/->find(itr, s).lock(); |
46 | | - // 新Nodeの作成 |
47 | | - auto newNode = std::make_shared<Node>( |
48 | | - m_size + 2, (suffixLinkFrom->m_edges.find(s[itr]) == |
49 | | - suffixLinkFrom->m_edges.end()) |
50 | | - ? suffixLinkFrom->m_edges.find(' ')->second |
51 | | - : suffixLinkFrom->m_edges.find(s[itr])->second); |
52 | | - m_edges.emplace(s[itr], newNode); |
53 | | - return std::weak_ptr<Node>(newNode); |
54 | | - } |
55 | | - |
56 | | - public: |
57 | | - // constructor |
58 | | - Node(int size, const std::weak_ptr<Node>& suffixLink) |
59 | | - : m_size(size), m_suffixLink(suffixLink) {} |
60 | | - Node() : m_size(-1) {} |
61 | | - |
62 | | - // 次サイズの回文を追加 |
63 | | - auto add(int itr, const std::string& s) { |
64 | | - auto addRoot = find(itr, s).lock(); |
65 | | - auto nextNode = |
66 | | - (addRoot->m_edges.find(s[itr]) == addRoot->m_edges.end()) |
67 | | - ? addRoot->create(itr, s) |
68 | | - : std::weak_ptr<Node>(addRoot->m_edges.find(s[itr])->second); |
69 | | - nextNode.lock()->m_itrs.emplace_back(itr); |
70 | | - return nextNode; |
71 | | - } |
| 26 | + auto add_edge(char c, int idx) -> void { edges.emplace_back(c, idx); } |
72 | 27 |
|
73 | | - // debug用 |
74 | | - auto outputTree(const std::string& s) const -> void { |
75 | | - if (m_size <= 0) { |
76 | | - std::cerr << "root"; |
| 28 | + auto add_itr(int itr) -> void { |
| 29 | + if (first_itr == -1) { |
| 30 | + first_itr = itr; |
77 | 31 | } else { |
78 | | - // 段 |
79 | | - for (int i = 0; (i < (m_size + 1) / 2); ++i) { std::cerr << " |"; } |
80 | | - std::cerr << "- " << s.substr(*m_itrs.begin() - m_size + 1, m_size); |
81 | | - // 右itr |
82 | | - std::cerr << " [ "; |
83 | | - for (const auto& itr : m_itrs) { std::cerr << itr << " "; } |
84 | | - std::cerr << "] "; |
85 | | - // suffix link |
86 | | - // auto p = m_suffixLink.lock(); |
87 | | - // std::cerr << "{" << s.substr(*p->m_itrs.begin() - p->m_size + 1, |
88 | | - // p->m_size) << "} "; |
89 | | - } |
90 | | - std::cerr << "\n"; |
91 | | - for (const auto& edge : m_edges) { |
92 | | - if (m_size == -1 && edge.first == ' ') { continue; } |
93 | | - edge.second->outputTree(s); |
| 32 | + rest_itrs.push_back(itr); |
94 | 33 | } |
95 | 34 | } |
96 | 35 |
|
97 | | - // rootを決定 |
98 | | - auto isOddRoot(const std::weak_ptr<Node>& evenRoot) { |
99 | | - m_suffixLink = weak_from_this(); |
100 | | - m_edges.emplace(' ', evenRoot); |
| 36 | + auto get_itrs() const -> std::vector<int> { |
| 37 | + if (first_itr == -1) { return {}; } |
| 38 | + std::vector<int> result; |
| 39 | + result.reserve(1 + rest_itrs.size()); |
| 40 | + result.push_back(first_itr); |
| 41 | + result.insert(result.end(), rest_itrs.begin(), rest_itrs.end()); |
| 42 | + return result; |
101 | 43 | } |
| 44 | + }; |
102 | 45 |
|
103 | | - // ラムダ式の実行 |
104 | | - template <class Lambda> |
105 | | - auto runLambda(const Lambda& lambda) { |
106 | | - if (m_size > 0) { lambda(m_size, m_itrs); } |
| 46 | + const std::string m_s; |
| 47 | + std::vector<Node> m_nodes; |
| 48 | + static constexpr int ROOT_ODD = 0; |
| 49 | + static constexpr int ROOT_EVEN = 1; |
| 50 | + |
| 51 | + auto find(int node_idx, int itr) const -> int { |
| 52 | + while (true) { |
| 53 | + int size = m_nodes[node_idx].size; |
| 54 | + if (size == -1) { return node_idx; } |
| 55 | + if (itr - size - 1 >= 0 && m_s[itr] == m_s[itr - size - 1]) { |
| 56 | + return node_idx; |
| 57 | + } |
| 58 | + node_idx = m_nodes[node_idx].suffix_link; |
107 | 59 | } |
| 60 | + } |
108 | 61 |
|
109 | | - /* |
110 | | - * lambda: (int size, list<int> rItr) -> void |
111 | | - */ |
112 | | - template <class Lambda, class SuffixLinkLambda = decltype(nullLambda)> |
113 | | - auto dfs_edges(const Lambda& lambda, |
114 | | - const SuffixLinkLambda& slLambda = nullLambda) -> void { |
115 | | - std::stack<std::shared_ptr<Node>, std::vector<std::shared_ptr<Node>>> |
116 | | - stk; |
117 | | - stk.emplace(this->weak_from_this().lock()); |
118 | | - while (!stk.empty()) { |
119 | | - auto p = stk.top(); |
120 | | - stk.pop(); |
121 | | - p->runLambda(lambda); |
122 | | - p->m_suffixLink.lock()->runLambda(slLambda); |
123 | | - for (const auto& [_, next_p] : p->m_edges) { |
124 | | - // std::cerr << p->m_size << " -> " << next_p->m_size << std::endl; |
125 | | - stk.emplace(next_p); |
126 | | - } |
127 | | - } |
| 62 | + auto add(int node_idx, int itr) -> int { |
| 63 | + int add_root = find(node_idx, itr); |
| 64 | + char c = m_s[itr]; |
| 65 | + |
| 66 | + int existing = m_nodes[add_root].find_edge(c); |
| 67 | + if (existing != -1) { |
| 68 | + m_nodes[existing].add_itr(itr); |
| 69 | + return existing; |
128 | 70 | } |
129 | | - }; |
130 | 71 |
|
131 | | - // 対象となる文字列 |
132 | | - const std::string m_s; |
| 72 | + int new_size = m_nodes[add_root].size + 2; |
| 73 | + int suffix_link_from = find(m_nodes[add_root].suffix_link, itr); |
| 74 | + |
| 75 | + int new_suffix_link = m_nodes[suffix_link_from].find_edge(c); |
| 76 | + if (new_suffix_link == -1) { new_suffix_link = ROOT_EVEN; } |
133 | 77 |
|
134 | | - // 偶数長,奇数長のPalindromicTreeの根(0, -1) |
135 | | - std::shared_ptr<Node> m_rootOdd; |
136 | | - std::shared_ptr<Node> m_rootEven; |
| 78 | + int new_idx = static_cast<int>(m_nodes.size()); |
| 79 | + m_nodes.emplace_back(new_size, new_suffix_link); |
| 80 | + m_nodes[new_idx].add_itr(itr); |
| 81 | + m_nodes[add_root].add_edge(c, new_idx); |
| 82 | + |
| 83 | + return new_idx; |
| 84 | + } |
137 | 85 |
|
138 | 86 | public: |
139 | | - // constructor |
140 | | - PalindromicTree(const std::string& s) |
141 | | - : m_s(s), |
142 | | - m_rootOdd(std::make_shared<Node>()), |
143 | | - m_rootEven(std::make_shared<Node>(0, m_rootOdd)) { |
144 | | - m_rootOdd->isOddRoot(m_rootEven); |
145 | | - auto root = m_rootOdd; |
146 | | - for (int r = 0; r < static_cast<int>(s.size()); ++r) { |
147 | | - root = root->add(r, s).lock(); |
| 87 | + PalindromicTree(const std::string& s) : m_s(s) { |
| 88 | + m_nodes.reserve(s.size() + 2); |
| 89 | + m_nodes.emplace_back(-1, ROOT_ODD); |
| 90 | + m_nodes.emplace_back(0, ROOT_ODD); |
| 91 | + |
| 92 | + int cur = ROOT_ODD; |
| 93 | + for (int i = 0; i < static_cast<int>(s.size()); ++i) { cur = add(cur, i); } |
| 94 | + |
| 95 | + m_nodes.shrink_to_fit(); |
| 96 | + for (auto& node : m_nodes) { |
| 97 | + node.edges.shrink_to_fit(); |
| 98 | + node.rest_itrs.shrink_to_fit(); |
148 | 99 | } |
149 | 100 | } |
150 | 101 |
|
151 | | - /* |
152 | | - * lambda: (int size, list<int> rItr) -> void |
153 | | - */ |
154 | 102 | template <class Lambda> |
155 | | - auto dfs_edges(const Lambda& lambda) { |
156 | | - m_rootOdd->dfs_edges(lambda); |
| 103 | + auto dfs_edges(const Lambda& lambda) const -> void { |
| 104 | + std::stack<int, std::vector<int>> stk; |
| 105 | + stk.push(ROOT_ODD); |
| 106 | + stk.push(ROOT_EVEN); |
| 107 | + |
| 108 | + while (!stk.empty()) { |
| 109 | + int idx = stk.top(); |
| 110 | + stk.pop(); |
| 111 | + |
| 112 | + const auto& node = m_nodes[idx]; |
| 113 | + if (node.size > 0) { lambda(node.size, node.get_itrs()); } |
| 114 | + |
| 115 | + for (const auto& [_, next_idx] : node.edges) { stk.push(next_idx); } |
| 116 | + } |
157 | 117 | } |
158 | 118 |
|
159 | | - /* |
160 | | - * かなり強引な実装 |
161 | | - * lambda: (int from, int to) -> void |
162 | | - */ |
163 | 119 | template <class Lambda> |
164 | | - auto dp_suffixLink(const Lambda& lambda) { |
165 | | - // 森の生成,探索順序の決定 |
166 | | - int from; |
167 | | - std::unordered_map<int, int> graph; |
168 | | - std::vector<int> orderCount(m_s.size()); |
169 | | - m_rootOdd->dfs_edges( |
170 | | - [&](int, const std::list<int>& rItrs) { from = rItrs.front(); }, |
171 | | - [&](int, const std::list<int>& rItrs) { |
172 | | - int to = rItrs.front(); |
173 | | - graph.emplace(from, to); |
174 | | - ++orderCount[to]; |
175 | | - }); |
176 | | - // 探索順序に従って処理 |
177 | | - std::queue<int, std::list<int>> q; |
| 120 | + auto dp_suffixLink(const Lambda& lambda) const -> void { |
| 121 | + std::vector<int> order_count(m_s.size(), 0); |
| 122 | + std::vector<std::vector<int>> graph(m_s.size()); |
| 123 | + |
| 124 | + for (int idx = 2; idx < static_cast<int>(m_nodes.size()); ++idx) { |
| 125 | + const auto& node = m_nodes[idx]; |
| 126 | + if (node.first_itr == -1) { continue; } |
| 127 | + |
| 128 | + int from = node.first_itr; |
| 129 | + int sl_idx = node.suffix_link; |
| 130 | + if (sl_idx >= 2 && m_nodes[sl_idx].first_itr != -1) { |
| 131 | + int to = m_nodes[sl_idx].first_itr; |
| 132 | + graph[from].push_back(to); |
| 133 | + ++order_count[to]; |
| 134 | + } |
| 135 | + } |
| 136 | + |
| 137 | + std::queue<int> q; |
178 | 138 | for (int i = 0; i < static_cast<int>(m_s.size()); ++i) { |
179 | | - if (orderCount[i] == 0) { q.emplace(i); } |
| 139 | + if (order_count[i] == 0) { q.push(i); } |
180 | 140 | } |
| 141 | + |
181 | 142 | while (!q.empty()) { |
182 | 143 | int f = q.front(); |
183 | 144 | q.pop(); |
184 | | - auto range = graph.equal_range(f); |
185 | | - for (auto itr = range.first; itr != range.second; ++itr) { |
186 | | - int t = itr->second; |
187 | | - --orderCount[t]; |
| 145 | + for (int t : graph[f]) { |
| 146 | + --order_count[t]; |
188 | 147 | lambda(f, t); |
189 | | - if (orderCount[t] == 0) { q.emplace(t); } |
| 148 | + if (order_count[t] == 0) { q.push(t); } |
190 | 149 | } |
191 | 150 | } |
192 | 151 | } |
193 | | - |
194 | | - // debug用 |
195 | | - auto outputTree() { |
196 | | - std::cerr << m_s << std::endl; |
197 | | - std::cerr << "-- even --\n"; |
198 | | - m_rootEven->outputTree(m_s); |
199 | | - std::cerr << "-- odd --\n"; |
200 | | - m_rootOdd->outputTree(m_s); |
201 | | - } |
202 | 152 | }; |
203 | 153 | } // namespace mtd |
0 commit comments