#218-[后缀数组]后缀排序

Description

读入一个由小写字母构成的字符串,求每个后缀的排名以及相邻两个后缀的LCP长度。

Input

一行一个字符串。

Output

第一行用空格隔开的n个数,n为字符串长度,按顺序依次为第1到第n个后缀在所有后缀里面的排名。

第一行用空格隔开的n个数,第i个数表示排名为i的后缀和排名为i-1的后缀的LCP长度,第一个数恒为0。

aabaaaab
  • Sample Input

4 6 8 1 2 3 5 7
0 3 2 3 1 2 0 1
  • Sample Output

HINT

n≤50000

Updated By MCHacker

后缀数组模板

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int MAXN = 50010;

int sa[MAXN], rnk[MAXN], height[MAXN], c[MAXN], t[MAXN], t2[MAXN];
char s[MAXN];

void get_sa(int n, int m) { // 找排名
	int *x=t, *y=t2;
	for (int i=0; i<m; ++i) c[i]=0; // 桶清空
	for (int i=0; i<n; ++i) ++c[x[i]=s[i]]; // 把字符塞进去
	for (int i=1; i<m; ++i) c[i]+=c[i-1]; // 前缀和
	for (int i=n-1; i>=0; --i) sa[--c[x[i]]]=i; // 全部放sa里去
	for (int k=1; k<=n; k<<=1) { // 倍增
		int p=0;
		for (int i=n-k; i<n; ++i) y[p++]=i;
		for (int i=0; i<n; ++i) {
			if (sa[i]>=k) y[p++]=sa[i]-k;
		}
		for (int i=0; i<m; ++i) c[i]=0; // 同上
		for (int i=0; i<n; ++i) ++c[x[y[i]]];
		for (int i=1; i<m; ++i) c[i]+=c[i-1];
		for (int i=n-1; i>=0; --i) sa[--c[x[y[i]]]]=y[i];
		swap(x, y); p=0; x[sa[0]]=p++;
		for (int i=1; i<n; ++i) {
			x[sa[i]] = ((y[sa[i-1]]==y[sa[i]])&&(y[sa[i-1]+k]==y[sa[i]+k]))?p-1:p++;
		}
		if (p>=n) break;
		m = p;
	}
}
void get_height(int n) { // 找LCP
	for (int i=0; i<n; ++i) rnk[sa[i]]=i; // 反取排名
	int k=0;
	for (int i=0; i<n; ++i) {
		if (!rnk[i]) continue;
		if (k>0) --k; // 据公式取得LCP最小值
		int j = sa[rnk[i]-1];
		while (s[i+k]==s[j+k]) ++k; // 暴力
		height[rnk[i]]=k;
	}
}
int main() {
	scanf("%s", s); int n=strlen(s), m=0;
	for (int i=0; i<n; ++i) m=max(m, int(s[i])); // 取字符集大小
	get_sa(n, m+1); get_height(n);
	for (int i=0; i<n; ++i) printf("%d ", rnk[i]+1);
	printf("\n");
	for (int i=0; i<n; ++i) printf("%d ", height[i]);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值