后缀数组学习笔记--sa和rnk数组

学了后缀自动机,切了寥寥几道字符串题发现就切不动了,问了sw和yzy大佬说其他题大多要用后缀数组,原来觉得学了后缀自动机就不用后缀数组这玩意了,没想到它也是很有用的,没办法再去恶补一波。。

后缀数组就是搞出字符串所有后缀给它排个序,sa[i]表示排第i的是哪个,rnk[i]表示i排哪,显然这两个是互逆的,求sa就能求rnk了

sa的求法主要就是一个倍增算法,算出某一长度的更新该长度乘2的。不过其中恶心的是直接用sort复杂度nloglog爆炸,一定要手写桶排来搞双关键字排序保证复杂度是nlog,导致这玩意思想很好懂代码贼难写,网上看了几个板子,学着写了一个看起来不错的。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int x[N],rnk[N],sa[N],y[N],tax[N],n,m;
char s[N];
void rsort()//双关键字排序,x当前在排的第一关键字,y第二关键字排名为i的位置 
{
	for(int i=1;i<=m;i++)tax[i]=0;
	for(int i=1;i<=n;i++)tax[x[i]]++;
	for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
	for(int i=n;i>=1;i--)sa[tax[x[y[i]]]--]=y[i];
}
void cal_sa()
{
	int num;
	m=130;
	for(int i=1;i<=n;i++)x[i]=s[i],y[i]=i;//要注意y[i]表示的是第二关键字排第i的是哪
	rsort();
	for(int l=1;;l<<=1)//倍增
	{
		num=0;
		for(int i=n-l+1;i<=n;i++)y[++num]=i;//这些位置第二维关键字不存在,第二维排名靠前
		for(int i=1;i<=n;i++)
			if(sa[i]>l)y[++num]=sa[i]-l;//按前一次所得名次得到这一次第二维排名
		rsort();
		swap(x,y);
		x[sa[1]]=1,num=1;
		for(int i=2;i<=n;i++)
			x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+l]==y[sa[i]+l])?num:++num;
		if(num==n)break;
		else m=num;	
	}
	for(int i=1;i<=n;i++)rnk[sa[i]]=i;
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	cal_sa();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值