UOJ Logo kczno1的博客

博客

suffix array模板

2017-01-25 21:25:39 By kczno1

$O(nlogn)$版

要注意:
计数排序后面一定要逆序加回去,这样才能保证原来的顺序不被破坏

int sa[N],q1[N],q2[N],*rank=q1,*temp=q2;
//sa[i] suffix array 后缀数组 第i名的起始位置
//rank[i] 第i个起始位置的rank 
char s[N];
int num[N];

int n,i;
void get_sa()
{
    int m=255;
    for (i=1;i<=n;++i) ++num[s[i]];
    for (i=1;i<=m;++i) num[i]+=num[i-1];
    for (i=n;i;--i) sa[num[s[i]]--]=i;
    int last,now;
    m=rank[last=sa[1]]=1;
    for (i=2;i<=n;++i) 
    {
        now=sa[i];
        if (s[now]!=s[last]) ++m;
        rank[last=now]=m;
    }

    for (int l=1;m<n;l<<=1)//rank[i],rank[i+l]作关键字
    {
        //先以rank[i+l]作关键字排序 
        int top=0;
        //i>n-l的 i+l已经超出 直接放进来 
        for (i=n-l+1;i<=n;++i) temp[++top]=i;
        //i<=n-l的 可以利用上一次的sa
        for (i=1;i<=n;++i)
        if (sa[i]>l) temp[++top]=sa[i]-l;

        //在temp的基础上 以rank[i]为关键字 计数排序 
        memset(num,0,m+1<<2);
        for (i=1;i<=n;++i) ++num[rank[i]];
        for (i=2;i<=m;++i) num[i]+=num[i-1];
        for (i=n;i;--i) sa[num[rank[temp[i]]]--]=temp[i];

        std::swap(rank,temp);//temp存储原来的rank,来比较是否一样
        m=rank[last=sa[1]]=1;
        for (i=2;i<=n;++i)
        {
            now=sa[i];
            if (!(temp[now]==temp[last]&&temp[now+l]==temp[last+l])) ++m;
            rank[last=now]=m; 
        }
    } 
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。