P3809 【模板】后缀排序
【模板】后缀排序
题目背景
这是一道模板题。
题目描述
读入一个长度为
输入格式
一行一个长度为
输出格式
一行,共
样例 #1
样例输入 #1
ababa
样例输出 #1
5 3 1 4 2
提示
文字理解先参考注释
绝对不是我想咕
#include<bits/stdc++.h> using namespace std; const int N=1e6+5; char s[N]; int n,m; int x[N],y[N],c[N],sa[N]; void get_SA() { for(int i=1;i<=n;i++){++c[x[i]=s[i]];}//x:第一关键字 for(int i=2;i<=m;i++){c[i]+=c[i-1];}//c:一个桶,用来统计在x[i]这个关键字之前有多少个字符串,以此得出每一个字符串的排名 for(int i=n;i;i--){sa[c[x[i]]--]=i;}//将对应的排名映射到答案中 for(int k=1;k<=n;k<<=1) { int cnt=0; for(int i=n-k+1;i<=n;i++) { //第i种第一个关键字 //可理解为一个编号 y[++cnt]=i;//y:第二关键字,注意:此处的y并非第二关键字的值,而是一个指针,它表示在第一关键字编号为i的字符串在第二关键字中排在cnt的位置(实在不行参考后面统计答案时都写法) //对于第二关键字被映射到[n-k+1,n]的节点,他本身是没有第二关键字的,排在队头 (或者说是表示第二关键字为排名为cnt的字符串的第一关键字的标号是i) } for(int i=1;i<=n;i++) { if(sa[i]>k)//这个点在后缀数组中的位置(即第一关键字排序中的位置比k大) { y[++cnt]=sa[i]-k;//将这一个点映射到的点(不是本身),排入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=2;i<=m;i++){c[i]+=c[i-1];} //初始化并重新统计第一关键字的桶 for(int i=n;i;i--) { //y[i]:当前要确定排名的字符串的编号 //i:他在第二关键字中的排名 sa[c[x[y[i]]]--]=y[i];y[i]=0; //从后往前:第一关键字相同的字符串,第二关键字靠后的排名靠后 //(c[]数组一直自减,后遍历到的点说明其排名靠前) } swap(x,y);//交换x,y当前的x将作为下一次的y参与排序 x[sa[1]]=1;cnt=1; for(int i=2;i<=n;i++) { //重新生成下一次排序的x cnt+=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k])^1;//如果当前节点和其对应的映射的第一关键字(的值,并非排名)完全相同,那么他们在下一次排序中的新第一关键字也相同 x[sa[i]]=cnt; } if(n==cnt)break; m=cnt; } } void work() { scanf("%s",s+1); n=strlen(s+1); m=122; get_SA(); for(int i=1;i<=n;i++) { printf("%d ",sa[i]); } } int main() { freopen("P3809.in","r",stdin);freopen("P3809.out","w",stdout); work(); }