概要

ダブリングしながら Suffix Array を計算する。

計算量

\(O(N \log^2 N)\)

実装

#include<string>
#include<algorithm>
using namespace std;

#define L (1 << 17)

struct SuffixArray {
  int tmp[L];
  int rank[L], sa[L], lcp[L], n;
  string s;

  SuffixArray(string s) : s(s) {}

  void construct_suffix() {
    n = s.length();
    for(int i=0; i<=n; ++i) {
      sa[i] = i;
      rank[i] = (i < n ? s[i] : -1);
    }

    int k = 1;
    auto sa_cmp = [=](int i, int j) -> bool {
      if(rank[i] != rank[j]) {
        return rank[i] < rank[j];
      }
      int ri = (i+k <= n ? rank[i+k] : -1);
      int rj = (j+k <= n ? rank[j+k] : -1);
      return ri < rj;
    };
    while(k <= n) {
      sort(sa, sa + n+1, sa_cmp);
      tmp[sa[0]] = 0;
      for(int i=1; i<=n; ++i) {
        tmp[sa[i]] = tmp[sa[i-1]] + sa_cmp(sa[i-1], sa[i]);
      }
      for(int i=0; i<=n; ++i) rank[i] = tmp[i];
      k <<= 1;
    }
  }

  void construct_lcp() {
    for(int i=0; i<=n; ++i) lcp[i] = -1, 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;
      while(j + h < n && i + h < n && s[j+h] == s[i+h]) ++h;
      lcp[rank[i] - 1] = h;
    }
  }
};

参考

  • 秋葉拓哉, 岩田陽一, and 北川宜稔. "プログラミングコンテストチャレンジブック." (2010).


戻る