SA-IS

一开始写的方便理解的版本:

#include<cstdio>
#include<cstring>

const int MAX_LEN = 1e6 + 5;

class SuffixArray {
 private:
  enum type_t{L = 0, S};
  bool isLMS(type_t *type, int loc) {
    if(loc <= 0) return false;
    if(type[loc] != S) return false;
    if(type[loc - 1] != L) return false;
    return true;
  }
  template<typename T>
  bool sameLMS(T str, type_t *type, int i, int j) {
    if(i == -1 || j == -1) return false;
    int k = -1;
    while(true) {
      ++k;
      if(str[i + k] != str[j + k]) return false;
      if(type[i + k] != type[j + k]) return false;
      if(k == 0) continue;
      if(isLMS(type, i + k) != isLMS(type, j + k)) return false;
      if(isLMS(type, i + k)) break;
    }
    return true;
  }
  template<typename T>
  void inducedSort(T str, int len, int sigma, type_t *type, int *LMS, int LMSSize) {
    int *bucket = new int[sigma];
    int *buf = new int[sigma];
    memset(sa, -1, sizeof(sa[0]) * len);
    memset(bucket, 0, sizeof(bucket[0]) * sigma);
    for(int i = 0; i < len; ++i) {
      ++bucket[str[i]];
    }
    buf[0] = bucket[0];
    for(int i = 1; i < sigma; ++i) {
      buf[i] = buf[i - 1] + bucket[i];
    }
    for(int i = LMSSize - 1; i >= 0; --i) {
      sa[--buf[str[LMS[i]]]] = LMS[i];
    }

    buf[0] = 0;
    for(int i = 1; i < sigma; ++i) {
      buf[i] = buf[i - 1] + bucket[i - 1];
    }
    for(int i = 0; i < len; ++i) {
      if(sa[i] <= 0) continue;
      if(type[sa[i] - 1] != L) continue;
      sa[buf[str[sa[i] - 1]]++] = sa[i] - 1;
    }

    buf[0] = bucket[0];
    for(int i = 1; i < sigma; ++i) {
      buf[i] = buf[i - 1] + bucket[i];
    }
    for(int i = len - 1; i >= 0; --i) {
      if(sa[i] <= 0) continue;
      if(type[sa[i] - 1] != S) continue;
      sa[--buf[str[sa[i] - 1]]] = sa[i] - 1;
    }
    delete[] bucket;
    delete[] buf;
    return;
  }
  template<typename T>
  void sais(T str, int len, int sigma, int *LMS) {
    type_t *type = new type_t[len];
    type[len - 1] = S;
    for(int i = len - 2; i >= 0; --i) {
      type[i] = str[i] < str[i + 1] ? S : L;
      if(str[i] != str[i + 1]) continue;
      type[i] = type[i + 1];
    }

    int LMSSize = 0;
    for(int i = 0; i < len; ++i) {
      if(!isLMS(type, i)) continue;
      LMS[LMSSize++] = i;
    }

    inducedSort(str, len, sigma, type, LMS, LMSSize);
    int pre = -1;
    int cnt = 0;
    int *temp = new int[len];
    for(int i = 0; i < len; ++i) {
      if(!isLMS(type, sa[i])) continue;
      if(!sameLMS(str, type, pre, sa[i])) ++cnt;
      temp[sa[i]] = cnt - 1;
      pre = sa[i];
    }
    int *s1 = new int[LMSSize];
    LMSSize = 0;
    for(int i = 0; i < len; ++i) {
      if(!isLMS(type, i)) continue;
      s1[LMSSize++] = temp[i];
    }
    delete[] temp;

    int *nextLMS = new int[LMSSize];
    if(cnt < LMSSize) {
      sais(s1, LMSSize, cnt, nextLMS);
    } else {
      for(int i = 0; i < LMSSize; ++i) {
        sa[s1[i]] = i;
      }
    }
    delete[] s1;
    for(int i = 0; i < LMSSize; ++i) {
      nextLMS[i] = LMS[sa[i]];
    }

    inducedSort(str, len, sigma, type, nextLMS, LMSSize);
    delete[] nextLMS;
    delete[] type;
    return;
  }
 public:
  int sa[MAX_LEN];
  int rank[MAX_LEN];
  template<typename T>
  void init(T str, int len, int sigma) {
    int *LMS = new int[len];
    sais(str, len + 1, sigma, LMS);
    delete[] LMS;
    for(int i = 0; i < len; ++i) {
      sa[i] = sa[i + 1] + 1;
      rank[sa[i]] = i;
    }
  }
} sais;

char str[MAX_LEN];

int main() {
  scanf("%s", str);
  int len = strlen(str);
  sais.init(str, len, 128);
  for(int i = 0; i < len; ++i) {
    printf("%d ", sais.sa[i]);
  }
  return 0;
}

后来写的方便快速打出来的版本:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAX_LEN = 1e6 + 5;
const int SIGMA = 128;
char s[MAX_LEN];
int str[MAX_LEN << 1];
int type[MAX_LEN << 1];
int LMS[MAX_LEN << 1];
int sa[MAX_LEN];
int rank[MAX_LEN];
int height[MAX_LEN];
int cnt[MAX_LEN];
int cur[MAX_LEN];
void inducedsort(int *str, int len, int sigma, int *LMS, int LMSC, int *type) {
    #define PUSH_S(x) (sa[cur[str[x]]--] = x)
    #define PUSH_L(x) (sa[cur[str[x]]++] = x)
    std::fill_n(sa, len, -1), std::fill_n(cnt, sigma, 0);
    for(int i = 0; i < len; ++i) ++cnt[str[i]];
    for(int i = 1; i < sigma; ++i) cnt[i] += cnt[i - 1];
    for(int i = 0; i < sigma; ++i) cur[i] = cnt[i] - 1;
    for(int i = LMSC - 1; i >= 0; --i) PUSH_S(LMS[i]);
    for(int i = 1; i < sigma; ++i) cur[i] = cnt[i - 1];
    for(int i = 0; i < len; ++i) sa[i] > 0 && type[sa[i] - 1] == 0 && PUSH_L(sa[i] - 1);
    for(int i = 0; i < sigma; ++i) cur[i] = cnt[i] - 1;
    for(int i = len - 1; i >= 0; --i) sa[i] > 0 && type[sa[i] - 1] && PUSH_S(sa[i] - 1);
    #undef PUSH_S
    #undef PUSH_L
}
void sais(int *str, int len, int sigma, int *LMS, int *type) {
    type[len - 1] = 1;
    for(int i = len - 2; i >= 0; --i) type[i] = (str[i] == str[i + 1] ? type[i + 1] : str[i] < str[i + 1]);
    int LMSC = 0;
    rank[0] = -1;
    for(int i = 1; i < len; ++i) rank[i] = (type[i] && !type[i - 1]) ? (LMS[LMSC] = i, LMSC++) : -1;
    inducedsort(str, len, sigma, LMS, LMSC, type);
    int tot = -1;
    int *s1 = str + len;
    for(int i = 0, now, last; i < len; ++i) if(-1 != (now = rank[sa[i]])) {
        if(tot < 1 || LMS[now + 1] - LMS[now] != LMS[last + 1] - LMS[last]) ++tot;
        else for(int j = LMS[now], k = LMS[last]; j < LMS[now + 1]; ++j, ++k) if((str[j] << 1 | type[j]) != (str[k] << 1 | type[k])) {
            ++tot;
            break;
        }
        s1[last = now] = tot;
    }
    if(tot + 1 < LMSC) sais(s1, LMSC, tot + 1, LMS + LMSC, type + len);
    else for(int i = 0; i < LMSC; ++i) sa[s1[i]] = i;
    for(int i = 0; i < LMSC; ++i) s1[i] = LMS[sa[i]];
    inducedsort(str, len, sigma, s1, LMSC, type);
}
void SA() {
    int len = strlen(s);
    for(int i = 0; i < len; ++i) str[i] = s[i];
    sais(str, len + 1, SIGMA, LMS, type);
    for(int i = 0; i <= len; ++i) rank[sa[i]] = i;
    for(int i = 0, k = 0; i <= len; height[rank[i++]] = k) {
        k && --k;
        if(rank[i] != 0) while(str[i + k] == str[sa[rank[i] - 1] + k]) ++k;
    }
    return;
}
int main() {
    scanf("%s", s);
    SA();
    return 0;
}