【洛谷P3809】【模板】后缀排序

题目

题目链接:https://www.luogu.com.cn/problem/P3809
读入一个长度为 \(n\) 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 \(1\)\(n\)

思路

倍增求 SA 数组。
推荐 Blog 或者蓝书。

代码

#include <bits/stdc++.h>
using namespace std;

const int N=1000010;
int n,m,x[N],y[N],sa[N],c[N];
char ch[N];

void SA()
{
	for (int i=1;i<=n;i++) x[i]=ch[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[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;
		m=num;
		if (m==n) break;
	}
}

int main()
{
	scanf("%s",ch+1);
	n=strlen(ch+1); m=122;
	SA();
	for (int i=1;i<=n;i++)
		printf("%d ",sa[i]);
	return 0;
}
posted @ 2020-10-15 17:01  stoorz  阅读(88)  评论(0编辑  收藏  举报