后缀排序
题目描述
读入一个长度为 nn 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 11 到 nn。
输入输出格式
输入格式:
一行一个长度为 nn 的仅包含大小写英文字母或数字的字符串。
输出格式:
一行,共n个整数,表示答案。
输入输出样例
说明
n <= 10^6
思路:后缀数组模板题。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include<bits/stdc++.h> #define REP(i, a, b) for(int i = (a); i <= (b); ++ i) #define REP(j, a, b) for(int j = (a); j <= (b); ++ j) #define PER(i, a, b) for(int i = (a); i >= (b); -- i) using namespace std; template <class T> inline void rd(T &ret){ char c; ret = 0; while ((c = getchar()) < '0' || c > '9'); while (c >= '0' && c <= '9'){ ret = ret * 10 + (c - '0'), c = getchar(); } } const int maxn=1e6+10; char str[maxn]; int len,m,sa[maxn],rk[maxn],tp[maxn],ton[maxn]; void rsort(){ for(int i=1;i<=m;i++)ton[i]=0; for(int i=1;i<=len;i++)ton[rk[i]]++; for(int i=1;i<=m;i++)ton[i]+=ton[i-1]; for(int i=len;i>=1;i--)sa[ton[rk[tp[i]]]--]=tp[i]; } int super(){ for(int i=1;i<=len;i++)rk[i]=str[i],tp[i]=i; rsort(); for(int w=1,p=0;p<len&&w<=len;m=p,w*=2){ p=0; for(int i=len-w+1;i<=len;i++)tp[++p]=i; for(int i=1;i<=len;i++){ if(sa[i]>w)tp[++p]=sa[i]-w; } rsort(); swap(rk,tp); rk[sa[1]]=p=1; for(int i=2;i<=len;i++){ rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&(tp[sa[i-1]+w]==tp[sa[i]+w]))?p:++p; } if(p>=len)break; } } int main(){ cin>>str+1; len=strlen(str+1); m=127; super(); REP(i,1,len)cout<<sa[i]<<' '; return 0; }