suffix_array.cpp GitHub #include "../structure/monoid.cpp" #include "../structure/segment_tree.cpp" template <typename string_t> struct SuffixArray { struct SAComp { const int h; const std::vector<int> &g; SAComp(int h_, std::vector<int> &g_) : h(h_), g(g_) { ; } bool operator()(int a, int b) { return a != b && (g[a] != g[b] ? g[a] < g[b] : g[a + h] < g[b + h]); } }; int n; string_t str; std::vector<int> sa, lcp; SuffixArray(const string_t &t) : n(t.size()), str(t), sa(n + 1), lcp(n + 1) { // build SA std::vector<int> g(n + 1, 0), b(n + 1, 0); for (int i = 0; i <= n; ++i) { sa[i] = i; g[i] = str[i]; } std::sort(begin(sa), end(sa), SAComp(0, g)); for (int h = 1; b[n] != n; h *= 2) { SAComp comp(h, g); std::sort(sa.begin(), sa.end(), comp); for (int i = 0; i < n; ++i) b[i + 1] = b[i] + comp(sa[i], sa[i + 1]); for (int i = 0; i <= n; ++i) g[sa[i]] = b[i]; } // build LCP int h = 0; for (int i = 0; i <= n; ++i) b[sa[i]] = i; for (int i = 0; i <= n; ++i) { if (b[i]) { int j = sa[b[i] - 1]; while (j + h < n && i + h < n && str[j + h] == str[i + h]) ++h; lcp[b[i]] = h; } else { lcp[b[i]] = -1; } if (h > 0) --h; } } template <class Compare> int binary_search(const string_t &t) const { int m = t.size(); int lb = -1, ub = n + 1; while (lb + 1 < ub) { int mid = (lb + ub) / 2; if (Compare()(strncmp(str.c_str() + sa[mid], t.c_str(), m), 0)) lb = mid; else ub = mid; } return ub; } int lower_bound(const string_t &t) const { return binary_search<std::less<int>>(t); } int upper_bound(const string_t &t) const { return binary_search<std::less_equal<int>>(t); } int find(const string_t &t) const { const int m = t.size(); int res = lower_bound(t); return strncmp(str.c_str() + sa[res], t.c_str(), m) == 0 ? sa[res] : -1; } }; class LCP { int n; std::vector<int> mapsto; SegmentTree<RMQ<int>> seg; public: LCP(const std::string &str) : n(str.size()), mapsto(n), seg(n) { SuffixArray<std::string> sa(str); for (int i = 0; i < n; ++i) mapsto[sa.sa[i + 1]] = i; for (int i = 0; i < n - 1; ++i) seg.update(i, sa.lcp[i + 2]); } int query(int i, int j) { if (i == j) return n - i; i = mapsto[i]; j = mapsto[j]; return seg.query(std::min(i, j), std::max(i, j)); } }; Includes monoid.cpp segment_tree.cpp Back