后缀数组SA
OI-wiki上写得很好,建议直接按这个学。
后缀数组(Suffix Array)主要关系到两个数组:𝑠𝑎 和 𝑟𝑘
其中,𝑠𝑎[𝑖] 表示将所有后缀排序后第 𝑖 小的后缀的编号,也是所说的后缀数组。
𝑟𝑘[𝑖] 表示后缀 𝑖 的排名。
这两个数组满足性质:𝑠𝑎[𝑟𝑘[𝑖]] =𝑟𝑘[𝑠𝑎[𝑖]] =𝑖
\(sa[排名]=编号\)
\(rk[编号]=排名\)

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


复杂度O(nlog^2n) 。
Height数组

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

浙公网安备 33010602011771号