LG P3809 【模板】后缀排序

时间:2021-08-13
本文章向大家介绍LG P3809 【模板】后缀排序,主要包括LG P3809 【模板】后缀排序使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

贴模板

注意:\(\text{id}\) 表示第二关键字排序后(其实无需排序,利用上轮的 \(\text{sa}\) 值即可)相应的第一关键字的位置
计数排序为了稳定性最后确定位置时要倒着开始
复制的 \(\text{ork}\) 要开两倍

\(\text{Code}\)

#include <cstdio>
#include <cstring>
#define re register
using namespace std;

const int N = 1e6 + 5;
int n, sa[N], rk[N], cnt[N], id[N], ork[N << 1];
char s[N];

inline int comp(int x, int y, int w){return (ork[x] == ork[y]) && (ork[x + w] == ork[y + w]);}

inline void build_SA()
{
	int m = 300, p;
	for(re int i = 1; i <= n; i++) ++cnt[rk[i] = s[i]];
	for(re int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
	for(re int i = n; i; i--) sa[cnt[rk[i]]--] = i;
	
	for(re int w = 1; w < n; w <<= 1, m = p)
	{
		p = 0;
		for(re int i = n - w + 1; i <= n; i++) id[++p] = i;
		for(re int i = 1; i <= n; i++)
		if (sa[i] > w) id[++p] = sa[i] - w;
		
		for(re int i = 0; i <= m; i++) cnt[i] = 0;
		for(re int i = 1; i <= n; i++) ++cnt[rk[id[i]]];
		for(re int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];
		for(re int i = n; i; i--) sa[cnt[rk[id[i]]]--] = id[i];
		
		for(re int i = 1; i <= n; i++) ork[i] = rk[i];
		p = 0;
		for(re int i = 1; i <= n; i++)
		rk[sa[i]] = comp(sa[i], sa[i - 1], w) ? p : ++p;
		if (p >= n) break;
	}
}

int main()
{
	scanf("%s", s + 1), n = strlen(s + 1), build_SA();
	for(re int i = 1; i <= n; i++) printf("%d ", sa[i]);
}

原文地址:https://www.cnblogs.com/leiyuanze/p/15138906.html