膜拜大佬:https://www.cnblogs.com/victorique/p/8480093.html#autoid-1-3-1
題目:https://www.luogu.org/problemnew/show/P3809
簡單的後綴排序
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000500
using namespace std;
int x[N];//備用串
int sa[N];//每個字符串首字符當排名爲i時在輸入串中的位置
int y[N]; // 排名爲i的子串首字符(sa[i]所代表的字串的第k個字符)在原串的位置
int c[N];//先記錄各個字符的個數,求前綴和即表示,用來記錄每個字符最晚出現的排名位置
int wt[30];
int n,m=122;//串長度 z的ASCII值爲122
char s[N];//輸入串
void slove(){
for(int i=1;i<=n;++i) ++c[x[i]=s[i]];//備份輸入串同時記錄每個字符的個數
// c[a]=3;c[b]=7;
for(int i=2;i<=m;++i) c[i]+=c[i-1];// 記錄每個字符最晚出現的排名的位置
// c[a]=3;c[b]=7;
for(int i=n;i>=1;--i) sa[c[x[i]]--]=i;//記錄每個字符串首字符當排名爲i時在輸入串中的位置
// 位置 1 2 3 4 5
// a b a b a
// 排名 1 4 2 5 3 ---> sa[1]=1;sa[2]=3;sa[3]=5;sa[4]=2;sa[5]=4;
for(int k=1;k<=n;k<<=1){
int num=0;
for(int i=n-k+1;i<=n;++i) y[++num]=i;//輸入串的最後k個字符所在位置一定是y[1~k] 所在位置
// k==1時 y[1]=5; k==2時 y[1]=4,y[2]=5;
//y[]在每次循環中所代表的是 當關鍵字按照每個子串第k個字符所排序後第i位該字符在原串中的位置
//並不是所有的子串都有第k個字符 要保證sa[i]>k
//y[]中排名後n-k位第i位的字符所在的位置其實就是sa[]中排名第i的位置減k ;
//k==1時 sa[1]=1;sa[2]=3;sa[3]=5;sa[4]=2;sa[5]=4
// y[2]=2; y[3]=4; y[4]=1; y[5]=3;
for(int i=1;i<=n;++i){//將剩下的字符排序
if(sa[i]>k) y[++num]=sa[i]-k;
}
for(int i=1;i<=m;++i) c[i]=0;
for(int i=1;i<=n;++i) ++c[x[i]];
for(int i=2;i<=m;++i) c[i]+=c[i-1]; //c[]在之前的代碼中更改了需要重新賦值
for(int i=n;i>=1;--i){
//跟第17行代碼有異曲同工之妙 只是將用來排名的字符由首字符換成了子串的第k位
//此時sa[]已更新爲以子串前k+1個字符重新排序之後的結果
sa[c[x[y[i]]]--]=y[i];y[i]=0;
}
swap(x,y);//因爲需要用x[]來更新x[],而此時y[]串相當於爲空 剛好可以用
//此時的y相當於輸入串的備用串
x[sa[1]]=1;
num=1;
for(int i=2;i<=n;++i)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
//當sa[]位置上所代表的字符都不同時結束循環
if(num==n) break;
m=num;
}
for(int i=1;i<=n;i++)cout<<sa[i]<<" ";
}
int main(){
gets(s+1);//排名從1開始
n=strlen(s+1);
slove();
return 0;
}
/*
ababa
*/
emmm lcp還沒看懂 明天繼續研究