传送门

后缀数组,可能有一点点绕吧,核心就是围绕基数排序分第一关键字和第二关键字

不断倍增,合并第一关键字和第二关键字完成排序

详细过程就不展开了,解释起来蛮累的(看了几个小时了)

注释版

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
char s[maxn];
int x[maxn],y[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],n,m;
void get_sa()
{
	for(int i=1;i<=n;i++)	++c[x[i]=s[i]];//初始第一关键字就是自己
	for(int i=2;i<=m;i++)	c[i] += c[i-1];//得到每个关键字的最后一名
	for(int i=n;i>=1;i--)	sa[c[x[i]]--] = i;//排名为c[x[i]]的是i
	for(int k=1;k<=n;k<<=1)//k是第一,二关键字的步长 
	{
		int num = 0;
		for(int i=n-k+1;i<=n;i++)	y[++num] = i;
		//y表示第二关键字排名为num的数第一关键字的位置 
		//[n-k+1,n]是没有第二关键字的,排名在最前面 
		for(int i=1;i<=n;i++)	if( sa[i]>k )	y[++num] = sa[i]-k;
		//上一次排名为i的数,如果下标大于k,那么这次可以作为下标为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]; 
		for(int i=n;i>=1;i--)	sa[c[x[y[i]]]--] = y[i], y[i] = 0;
		//x[y[i]]表示的是第二关键字排民为i的第一关键字是什么,那么c[]--就是计算排名
		swap(x,y);
		x[sa[1]] = 1, num = 1;//根据y生成下一次的x
		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; 
		//意思是,只有当第一关键字和第二关键字都相等是,下一次的第一关键字排名才和本次相等	
		if( num==n )	break;
		m = num;//只有这么多种类型 
	}
	for(int i=1;i<=n;i++)	printf("%d ",sa[i] ); 
}
int main()
{
	scanf("%s",s+1);
	n = strlen( s+1 ); m = 122;
	get_sa();	
} 

无注释版

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
char s[maxn];
int x[maxn],y[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],n,m;
void get_sa()
{
	for(int i=1;i<=n;i++)	++c[x[i]=s[i]];
	for(int i=2;i<=m;i++)	c[i] += c[i-1];
	for(int i=n;i>=1;i--)	sa[c[x[i]]--] = i;
	for(int k=1;k<=n;k<<=1)
	{
		int num = 0;
		for(int i=n-k+1;i<=n;i++)	y[++num] = i;
		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]; 
		for(int i=n;i>=1;i--)	sa[c[x[y[i]]]--] = y[i], y[i] = 0;
		swap(x,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; 	
		if( num==n )	break;
		m = num;//只有这么多种类型 
	}
	for(int i=1;i<=n;i++)	printf("%d ",sa[i] ); 
}
void get_height()
{
	int k = 0;
	for(int i=1;i<=n;i++)	rk[sa[i]] = i;
	for(int i=1;i<=n;i++)
	{
		if( rk[i]==1 )	continue;//第一名height为0
		if( k )	k--; //h[i]>=h[i-1]-1
		int j = sa[rk[i]-1];
		while( j+k<=n&&i+k<=n&&s[i+k]==s[j+k] )	k++;
		height[rk[i]] = k; 
	}
	for(int i=1;i<=n;i++)	printf("%d ",height[i] );
}
int main()
{
	scanf("%s",s+1);
	n = strlen( s+1 ); m = 122;
	get_sa();	
}