第一次学后缀数组
被难哭了只能说大为震撼
后缀数组 可以将所有的后缀字典序进行排序
非常的巧妙 将后缀字典序排序
我们可以 使用 二分+哈希的方式 进行sort 重写 cmp
复杂度两个long*n
而后缀数组 有两种构建方法
倍增和DC3 DC3好难还没懂
写的是倍增
复杂度 n logn
里面数组非常晕 建议
看视频学习我太菜了
后面有最关键的一个证明
#include <bits/stdc++.h>
using namespace std;
//#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
#define fi first
#define se second
#define pb push_back
#define inf 1<<62
#define endl "\n"
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define de_bug(x) cerr << #x << "=" << x << endl
#define all(a) a.begin(),a.end()
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fer(i,a,b) for(int i=a;i<=b;i++)
#define der(i,a,b) for(int i=a;i>=b;i--)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
int n, m , k;
int sa[N], x[N], h[N];
int c[N], y[N];
int rk[N];
string s;
// sa[i]排名第i位的是第几个后缀
// h[i]是sa[i]与sa[i - 1]的最长公共前缀的长度 lcp
// y是按第二关键字排的情况下每个后缀的排名
void get_sa() {
for(int i = 1; i <= m; i++) c[i] = 0;
//用桶排的方式去排序
for(int i = 1; i <= n; i++) c[x[i] = s[i]]++;
for(int i = 2; i <= m; i++) c[i] += c[i - 1];
for(int i = n; i; i--) sa[c[x[i]]--] = i;
//每一轮倍增进行后缀排序
for(int k = 1; k <= n; k <<= 1) {
int num = 0;
for(int i = n - k + 1; i <= n; i++)y[ ++ num] = i;
//长度不够k的 第二关键字 为空 所以优先排序
//排名小于等于k的已经有序
//第sa[i]-k个后缀的第二关键字为第sa[i]个后缀
for(int i = 1; i <= n; i++)if(sa[i] > k)y[++num] = sa[i] - k;
//已经按照第二关键字排序好了
// y[i]表示以第二关键排序 排名为i的后缀的下标
//x[y[i]]表示按 第一关键字的排名
for(int i = 1; i <= m; i++)c[i] = 0;
for(int i = 1; i <= n; i++)c[x[i]]++;
for(int i = 1; i <= m; i++)c[i] += c[i - 1];
for(int i = n; i ; i--) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
for (int i = 1; i <= n; i++) swap(x[i], y[i]);
x[sa[1]] = 1, num = 1;
//继续离散化 如果没有相同的话 即num==n
for(int i = 2; i <= n; i++)
//如果第一关键字相同并且第二关键字也相同 那么我们就不能累计sun
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
if(num == n)break;
m = num;
}
}
// 有一个证明是 h[rk[i]]>=h[sa[rk[i]-1]]-1;
void get_height() {
for(int i = 1; i <= n; i++)rk[sa[i]] = i;
//rk[j]=i 第j个位置排名为i sa[i]=j 排名为i的位置为j
for(int i = 1, k = 0; i <= n; i++) {
if(rk[i] == 1)continue;
int j = sa[rk[i] - 1];
if(k)k--;
while(i + k <= n && j + k <= n && s[i + k] == s[j + k])k++;
h[rk[i]] = k;
}
}
void solve() {
cin >> s;
n = s.size();
m = 'z';
s = " " + s;
get_sa();
get_height();
for(int i = 1; i <= n; i++)cout << sa[i] << " \n"[i == n];
for(int i = 1; i <= n; i++)cout << h[i] << " \n"[i == n];
}
int main() {
IOS;
int _ ;
cin >> _;
while( _-- )
solve();
}