后缀数组模板

今天学了一下倍增求后缀数组,感觉还不错。
毕竟二分hash求后缀数组适用范围实在太小了

代码:

char s[Maxn];int n;
int t[Maxn],sa[Maxn],rank[Maxn],wr[Maxn],tmp[Maxn],y[Maxn];
/*y[i]排名为i的第二关键字的第一关键字的后缀开始位置*/ 
void get_sa(int m)
{
    /*先用基数排序求出第一次的rank和sa*/
    for(int i=1;i<=n;i++)t[rank[i]=s[i]]++;
    for(int i=1;i<=m;i++)t[i]+=t[i-1];
    for(int i=n;i;i--)sa[t[s[i]]--]=i;
    /*len为当前倍增的长度,mx为当前最大的排名,若mx>=n则意味着完成排序*/
    int len=1,mx=0; 
    while(mx<n)
    {
        int k=0;
        /*这个范围内的后缀的第二关键字是最小的*/
        for(int i=n-len+1;i<=n;i++)y[++k]=i;
        for(int i=1;i<=n;i++)if(sa[i]>len)y[++k]=sa[i]-len;
        /*得出y[i]后就可以直接开始基数排序了,wr[i]可以理解为第一次排序的s[i],为排序关键字*/
        for(int i=0;i<=m;i++)t[i]=0;
        for(int i=1;i<=n;i++)t[wr[i]=rank[y[i]]]++;
        for(int i=1;i<=m;i++)t[i]+=t[i-1];
        for(int i=n;i;i--)sa[t[wr[i]]--]=y[i];
        /*tmp存临时排名*/
        for(int i=1;i<=n;i++)tmp[i]=rank[i];
        int rk=1;rank[sa[1]]=1;
        for(int i=2;i<=n;i++)
        {
            if(tmp[sa[i]]!=tmp[sa[i-1]]||tmp[sa[i]+len]!=tmp[sa[i-1]+len])rk++;
            rank[sa[i]]=rk;
        }
        len<<=1;mx=rk;m=rk;
    }
}
/*设h[i]=height[rank[i]],有性质:h[i]>=h[i-1]-1,利用这个求height数组*/
int height[Maxn]; 
void get_height()
{
    for(int i=1;i<=n;i++)
    {
        int j=sa[rank[i]-1],k=height[rank[i-1]];
        if(k)k--;
        while(s[i+k]==s[j+k])k++;
        height[rank[i]]=k;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值