后缀数组SA

OI-wiki上写得很好,建议直接按这个学。

后缀数组(Suffix Array)主要关系到两个数组:𝑠𝑎 和 𝑟𝑘
其中,𝑠𝑎[𝑖] 表示将所有后缀排序后第 𝑖 小的后缀的编号,也是所说的后缀数组。
𝑟𝑘[𝑖] 表示后缀 𝑖 的排名。
这两个数组满足性质:𝑠𝑎[𝑟𝑘[𝑖]] =𝑟𝑘[𝑠𝑎[𝑖]] =𝑖

\(sa[排名]=编号\)
\(rk[编号]=排名\)

image

怎么求后缀数组

倍增求法。
其实质思想还是比较每个后缀的大小进行排名,只不过用倍增的方式把每个后缀“拼”起来。每次只需比较两部分,比较的块数也在不断减少,从而达到减小复杂度的效果。

批注 2026-07-03 165958

image

复杂度O(nlog^2n) 。

Height数组

批注 2026-07-04 173649

代码:

点击查看代码
for(int i=1;i<=n;i++)
{
	sa[i]=i, rk[i]=s[i];
}
for(w=1;w<n;w<<=1)
{
	sort(sa+1, sa+n+1, cmp);
	memcpy(lstrk, rk, sizeof(rk));
	int p=0;
	for(int i=1;i<=n;i++)
	{
		if(lstrk[sa[i]]==lstrk[sa[i-1]]&&lstrk[sa[i]+w]==lstrk[sa[i-1]+w])
		{
			rk[sa[i]]=p;
		}
		else rk[sa[i]]=++p;
	}
}
for(int i=1, k=0;i<=n;i++)
{
	if(rk[i]==0) continue;
	if(k) k--;
	while(s[i+k]==s[sa[rk[i]-1]+k]) k++;
	height[rk[i]]=k;
}

常见技巧

  1. 拼串。如果出现循环子串([JSOI2007] 字符加密,原串复制一遍拼在后面)、回文串(倒着往后拼)、给了多个串等情况,考虑把串拼在一起,注意有的题目需要在拼的串之间加上极小或极大字符。拼串后求SA,height即可处理多种匹配问题。
  2. 子串是后缀的前缀,因此某些比较子串的题,可以直接用height数组比。height数组非常万能。
  3. lcp(i,j)就是求min{height[i+1~j]},可以用RMQ快速处理。
  4. 可能与单调栈和单调队列结合,如[Usaco2006 Dec] Milk Patterns 产奶的模式 和 [bzoj3238][Ahoi2013] 差异。后者有个非常典的 trick:求数列每个区间最小值之和,考虑每个数作为最小值贡献区间的个数,转化为找出每个数左右第一个比它小的位置,根据乘法原理计算。 单调队列往往在height数组上搞。
  5. 可以与并查集结合。如[NOI2015] 品酒大会。思路非常巧妙,不需要在height数组上大费周章。

写的似乎有点简略。。

posted @ 2026-07-04 17:50  zhouyiran2011  阅读(10)  评论(0)    收藏  举报