#include<iostream>
#include<vector>
#include<numeric>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e6 + 5;
int n;
int rk[N << 1], sa[N], oldrk[N << 1], nsa[N], key2[N], cnt[N] = {0};
char s[N];
bool cmp(int x, int y, int w) {
return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w];
}
void sol(){
string s = ".";
string t;
cin >> t;
s += t;
n = t.size();
int scope = 127;
for (int i = 1; i <= n; ++i) ++cnt[rk[i] = s[i]];
for (int i = 1; i <= scope; ++i) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i;
int p = 0;
for (int w = 1; ; w <<= 1, scope = p) {
//第二关键字计数排序
p = 0;
for (int i = n; i + w > n; --i) nsa[++p] = i;
for (int i = 1; i <= n; ++i) if (sa[i] > w) nsa[++p] = sa[i] - w;
//第一关键字基数排序
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; ++i) ++cnt[key2[i] = rk[nsa[i]]];
for (int i = 1; i <= scope; ++i) cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i) sa[cnt[key2[i]]--] = nsa[i];
p = 0;
//得到sa数组,更新rk数组
memcpy(oldrk + 1, rk + 1, n * sizeof(int));
for (int i = 1; i <= n; i++) {
rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p;
}
if (p == n) {
for (int i = 1; i <= n; i++) sa[rk[i]] = i;
break;
}
}
for (int i = 1; i <= n; i++) cout << sa[i] << " ";
cout << "\n";
/*height数组:引理 height[rk[i]] >= height[rk[i - 1]] - 1*/
vector<int> h(n + 1);
int k = 0;
for (int i = 1; i <= n; i++) {
if (rk[i] == 1) continue;
if (k) k--;
while (i + k <= n && sa[rk[i] - 1] + k <= n && s[i + k] == s[sa[rk[i] - 1] + k]) k++;
h[rk[i]] = k;
}
/* lcp数组: lcp(sa[i], sa[j]) = min(height[i......j]) */
vector<vector<int>> lcp(n + 1, vector<int>(n + 1));
vector<vector<int>> st(n + 1, vector<int>(100, INT_MAX));
for (int i = 1; i <= n; i++) st[i][0] = h[i];
for (int i = n; i >= 1; i--) {
for (int j = 1; i + (1 << j) - 1 <= n; j++) {
st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int a = rk[i], b = rk[j];
if (a == b) {
lcp[i][j] = 1;
continue;
}
if (a > b) swap(a, b);
a++;
int len = log2(b - a + 1);
lcp[i][j] = min(st[a][len], st[b - (1 << len) + 1][len]);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
sol();
return 0;
}
后缀数组模板
于 2022-10-11 21:08:25 首次发布