1. 程式人生 > 其它 >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]);
}