请参看@自为风月马前卒的博客,本博客只是为了帮助我自己理解。
原作者:自为风月马前卒 大佬
个人博客
出处
后缀数组的定义:以
a
a
b
a
a
a
a
b
aabaaaab
aabaaaab为例:
它的后缀数组有:
1.
a
a
b
a
a
a
a
b
aabaaaab
aabaaaab;
2.
a
b
a
a
a
a
b
abaaaab
abaaaab;
3.
b
a
a
a
a
b
baaaab
baaaab;
4.
a
a
a
a
b
aaaab
aaaab;
5.
a
a
a
b
aaab
aaab;
6.
a
a
b
aab
aab;
7.
a
b
ab
ab;
8.
b
b
b
排名应如下:
rank1:
a
a
a
a
b
aaaab
aaaab;
rank2:
a
a
b
aab
aab;
rank3:
b
b
b;
rank4:
a
a
b
a
a
a
a
b
aabaaaab
aabaaaab;
rank5:
a
b
a
a
a
a
b
abaaaab
abaaaab;
rank6:
b
a
a
a
a
b
baaaab
baaaab;
rank7:
a
a
a
b
aaab
aaab;
rank8:
a
b
ab
ab;
(PS:哪位大佬能告诉我为什么这样排啊
Q
A
Q
QAQ
QAQ)
求法:
1.更新第一关键字(
r
a
n
k
rank
rank,
t
p
tp
tp);
2.由第一关键字更新
s
a
sa
sa;
3.从
1
1
1枚举
w
w
w,更新第二关键字:
t
p
tp
tp;
4.由第二关键字更新
s
a
sa
sa;
5.更新
r
a
n
k
rank
rank(
r
a
n
k
[
s
a
[
i
]
]
=
i
rank [ sa [ i ] ]=i
rank[sa[i]]=i);
6.如果计数器
p
=
=
l
e
n
−
1
p==len-1
p==len−1输出
s
a
sa
sa,否则倍增
w
w
w,重复第3~5步;
Code
//洛谷R19784739
#include<cstdio>
#include<cstring>
#define maxn 1000005
using namespace std;
int len,mx;
int sa[maxn],tp[maxn],rank[maxn],t[maxn];//t[i]是桶
char s[maxn];
void qsort()
{
for(int i=0;i<=mx;++i)t[i]=0;
for(int i=1;i<=len;++i)t[rank[i]]++;//桶排序
for(int i=1;i<=mx;++i)t[i]+=t[i-1];//前缀和
for(int i=len;i>=1;--i)sa[t[rank[tp[i]]]--]=tp[i];//求当前的后缀数组排名
}
void suffixsort()
{
mx=75;
for(int i=1;i<=len;++i)
{
rank[i]=s[i]-'0'+1;
tp[i]=i;
}//rank[i]是s[i]的ASKII排名,tp[i]是原始排名
qsort();
for(int w=1,p=0;p<=len-1;mx=p,w<<=1)
{
//w:当前倍增的长度,w = x表示已经求出了长度为x的后缀的排名,现在要更新长度为2x的后缀的排名
//p表示不同的后缀的个数,很显然原字符串的后缀都是不同的,因此p = N时可以退出循环
p=0;//计数器
for(int i=1;i<=w;++i)tp[++p]=len-w+i;
for(int i=1;i<=len;++i)
{
if(sa[i]>w)
tp[++p]=sa[i]-w;
}
qsort();//用第二轮关键字求出sa
memcpy(tp,rank,sizeof(rank));//tp已经没用了
rank[sa[1]]=p=1;//更新
for(int i=2;i<=len;++i)
{
rank[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
}//看不懂QAQ
}//倍增求后缀数组
for(int i=1;i<=len;++i)
printf("%d ",sa[i]);
}//后缀数组排序
int main()
{
scanf("%s",s+1);
len=strlen(s+1);
suffixsort();
return 0;
}
我不生产代码,我只是代码的搬运工。