[后缀数组] Luogu P3809 后缀排序

题目描述

读入一个长度为 nn 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 11 到 nn。

 

题解

  • 板题

 

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #define N 1000010 
 5 using namespace std;
 6 int n,m=122,t[N],x[N],c[N],sa[N];
 7 char s[N];
 8 void get_SA()
 9 {
10     for (int i=1;i<=n;i++) c[x[i]=s[i]]++;
11     for (int i=2;i<=m;i++) c[i]+=c[i-1];
12     for (int i=n;i>=1;i--) sa[c[x[i]]--]=i;
13     for (int k=1;k<=n;k<<=1)
14     {
15         int p=0;
16         for (int i=n-k+1;i<=n;i++) t[++p]=i;
17         for (int i=1;i<=n;i++) if (sa[i]>k) t[++p]=sa[i]-k;
18         for (int i=1;i<=m;i++) c[i]=0;
19         for (int i=1;i<=n;i++) c[x[i]]++;
20         for (int i=2;i<=m;i++) c[i]+=c[i-1];
21         for (int i=n;i>=1;i--) sa[c[x[t[i]]]--]=t[i],t[i]=0;
22         swap(x,t);
23         p=1,x[sa[1]]=1;
24         for (int i=2;i<=n;i++) x[sa[i]]=(t[sa[i-1]]==t[sa[i]]&&t[sa[i-1]+k]==t[sa[i]+k])?p:++p; 
25         if (p==n) break;
26         m=p;
27     }
28     for (int i=1;i<=n;i++) printf("%d ",sa[i]);
29 }
30 int main()
31 {
32     scanf("%s",s+1),n=strlen(s+1),get_SA();    
33 }

 

posted @ 2019-07-28 11:00  BEYang_Z  阅读(150)  评论(0编辑  收藏  举报