library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub satanic0258/library

:heavy_check_mark: test/yosupo/SuffixArray.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/suffixarray"
#include <bits/stdc++.h>
#include "../../string/SuffixArray.hpp"

#define REP(w, n) for(int w=0; w<int(n); ++w)

int main(){
 std::string s;
 std::cin >> s;

 SuffixArray sa(s);
 REP(i, s.size()) {
  std::cout << sa.sa[i + 1] << (i + 1 == s.size() ? '\n' : ' ');
 }
}
#line 1 "test/yosupo/SuffixArray.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/suffixarray"
#include <bits/stdc++.h>
#line 1 "string/SuffixArray.hpp"
// @brief SuffixArray
// @shortcut SuffixArray
// @description SuffixArray+LCPの構築.SA-IS実装によりO(|S|).
// @docs string/SuffixArray.md
class SuffixArray {
private:
 const int n;
 std::vector<bool> t;
 std::vector<int> p1;

 void constructSA(const std::vector<int>& s, int K) {
  std::vector<int> B(K, 0);
  std::vector<int> start(K + 1, 0);
  std::vector<int> LMS(n, -1);
  std::vector<int> tmp(n, -1);

  auto inducedSort = [&](std::vector<int> & a) {
   std::vector<int> l(K), r(K);
   for (int i = 0; i < K; ++i) l[i] = start[i], r[i] = start[i + 1] - 1;

   for (const auto& i : a) {
    if (i > 0 && !t[i - 1]) a[l[s[i - 1]]++] = i - 1;
   }

   for (int ti = n - 1; ti >= 0; --ti) {
    int i = a[ti];
    if (i > 0 && t[i - 1]) a[r[s[i - 1]]--] = i - 1;
   }
  };

  { // create t (L/S-type)
   t[n - 1] = true;
   for (int i = n - 2; i >= 0; --i) {
    if (s[i] == s[i + 1]) t[i] = t[i + 1];
    else t[i] = (s[i] < s[i + 1]);
   }
  }
  { // create p1 (position of LMS), B (bucket size) and tmp
   for (int i = 0; i < n; ++i) {
    if (i > 0 && !t[i - 1] && t[i]) LMS[i] = p1.size(), p1.emplace_back(i);
    ++B[s[i]];
   }
   for (int i = 0; i < K; ++i) start[i + 1] = start[i] + B[i];
  }
  { // induced-sort LSM-substrings
   std::vector<int> r(K);
   for (int i = 0; i < K; ++i) r[i] = start[i + 1] - 1;
   for (int i : p1) tmp[r[s[i]]--] = i;

   inducedSort(tmp);
  }
  std::vector<int> s1(p1.size());
  bool conti = false;
  int K1 = 0;
  { // create s1
   std::vector<int> t1(p1.size()), t2(p1.size(), 0);
   int p = 0;
   for (int ti = 0; ti < n; ++ti) {
    int i = tmp[ti];
    if (LMS[i] != -1) t1[p++] = i;
   }

   // compress
   for (int si = 1; si < t2.size(); ++si) {
    int i = t1[si - 1], j = t1[si];
    if (s[i] != s[j]) {
     t2[si] = t2[si - 1] + 1;
     continue;
    }
    ++i; ++j;
    while (LMS[i] == -1 && LMS[j] == -1 && s[i] == s[j]) ++i, ++j;
    if (LMS[i] != -1 && LMS[j] != -1) {
     t2[si] = t2[si - 1];
     conti = true;
    }
    else {
     t2[si] = t2[si - 1] + 1;
    }
   }
   K1 = t2.back() + 1;

   // re-order
   for (int i = 0; i < t1.size(); ++i) s1[LMS[t1[i]]] = t2[i];
  }
  std::vector<int> sa1;
  { // create sa1 (sometime recursion)
   if (conti) {
    sa1 = SuffixArray(s1, K1).sa;
   }
   else {
    sa1.resize(s1.size());
    for (int i = 0; i < s1.size(); ++i) sa1[s1[i]] = i;
   }
  }
  { // create sa
   sa.resize(n, -1);
   std::vector<int> r(K);
   for (int i = 0; i < K; ++i) r[i] = start[i + 1] - 1;
   for (int pi = static_cast<int>(p1.size()) - 1; pi >= 0; --pi) {
    int i = p1[sa1[pi]];
    sa[r[s[i]]--] = i;
   }

   inducedSort(sa);
  }
 }

 void constructLCP(const std::vector<int> & s) {
  const int n = s.size() - 1;
  lcp.resize(n + 1);
  std::vector<int> rank(n + 1);
  for (int i = 0; i <= n; ++i) rank[sa[i]] = i;

  int h = 0;
  lcp[0] = 0;
  for (int i = 0; i < n; ++i) {
   int j = sa[rank[i] - 1];
   if (h > 0) --h;
   for (; j + h < n && i + h < n; ++h) if (s[j + h] != s[i + h]) break;
   lcp[rank[i] - 1] = h;
  }
 }

 SuffixArray(std::vector<int> s, int k) : n(s.size()), t(n) {
  constructSA(s, k); constructLCP(s);
 }
public:
 std::string str;
 std::vector<int> sa;
 std::vector<int> lcp;

 SuffixArray(const std::string & s_) : str(s_), n(s_.size() + 1), t(n) {
  int k = 0;
  std::vector<int> s(n);
  { // compress s
   std::vector<int> used(256, -1);
   used[0] = 0; s[n - 1] = 0;
   for (int i = 0; i < n - 1; ++i) used[s_[i]] = 0;
   for (int i = 0; i < 256; ++i) if (used[i] != -1) used[i] = k++;
   for (int i = 0; i < n - 1; ++i) s[i] = used[s_[i]];
  }
  constructSA(s, k);
  constructLCP(s);
 }

 void debug_show() const {
  std::cerr << "idx  " << " sa  " << "LCP  " << "suffix\n";
  for (int i = 0; i < n; ++i) {
   std::cerr << std::setw(3) << std::setfill(' ') << i << "  ";
   std::cerr << std::setw(3) << std::setfill(' ') << sa[i] << "  ";
   std::cerr << std::setw(3) << std::setfill(' ') << lcp[i] << "  ";
   std::cerr << str.substr(sa[i]) << "\n";
  }
 }
};
#line 4 "test/yosupo/SuffixArray.test.cpp"

#define REP(w, n) for(int w=0; w<int(n); ++w)

int main(){
 std::string s;
 std::cin >> s;

 SuffixArray sa(s);
 REP(i, s.size()) {
  std::cout << sa.sa[i + 1] << (i + 1 == s.size() ? '\n' : ' ');
 }
}
Back to top page