[MOBAN]后缀数组

wc早上讲了很骚气的字符串算法和骚气的具体数学,睡眠很香,发现不会课程的前置知识后缀数组ora,学一波 参考博客: https://www.cnblogs.com/RabbitHu/p/UOJ35.html https://www.cnblogs.com/victorique/p/8480093.html https://www.cnblogs.com/zwfymqz/p/8413523.html SA[i] 排名i的后缀的位置 RANK[i] suf[i]的排名 height[i] (关键)表示后缀sa[i]和后缀sa[i-1]的lcp(最长公共前缀),并且满足height[rk[i]]>= height[rk[i-1]]-1 既是位置上i的height >= i-1的height-1,这样我们可以线性求height LCP(i,j) = min: heghit[k] rank[i] < rank[k] <= rank[j] 可重叠最长重复子串 max:height 本质不同子串:LEN-sa[i]+1-height[i]
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;

const int maxn = 1e5+5;

char s[maxn];
int buf1[maxn],buf2[maxn],ton[maxn];
int n,sa[maxn],rnk[maxn],height[maxn];
void suffixsort() {
    int *x = buf1 , *y = buf2; int m = 127;
    //x,y临时数组,m基数排序最大值
    fill(ton,ton+m+1,0);//清空桶
    for(int i=1;i<=n;i++)  ton[ x[i] = s[i] ]++;
    for(int i=1;i<=m;i++) ton[i] += ton[i-1];
    for(int i=n;i>=1;i--) sa[ton[x[i]]--] = i;
    for(int k=1;k<=n;k<<=1) { //枚举比较长度的1/2
        int p = 0; //新桶字符串数
        for(int i=n-k+1;i<=n;i++) y[++p] = i;
        for(int i=1;i<=n;i++) {
            if(sa[i]>k) y[++p] = sa[i] - k;//加入第一关键字
        }
        //为第二关键字排序,保证在第一关键字相同的情况下第二关键字顺序
        fill(ton,ton+m+1,0);
        for(int i=1;i<=n;i++) ton[x[y[i]]]++;
        for(int i=1;i<=m;i++) ton[i] += ton[i-1];
        for(int i=n;i>=1;i--) sa[ton[x[y[i]]]--] = y[i];
        //为第一关键字排序
        swap(x,y);//y上一轮的字符构造出x现在新的一轮的值
        p = x[sa[1]] = 1;
        for(int i=2;i<=n;i++) {
            if(y[sa[i]]==y[sa[i-1]]&&y[sa[i-1]+k]==y[sa[i]+k]) x[sa[i]] = p;
            else x[sa[i]] = ++p;
        }
        m = p;
        if(m==n) break;
    }
    for(int i=1;i<=n;i++) rnk[sa[i]] = i;
    //sa保存排名i在哪儿,rnk保存i的排名
    for(int i=1,CD=0;i<=n;i++) {
        if(rnk[i]==1) continue;
        if(CD>0) CD--;
        int lst = sa[rnk[i]-1];
        while(s[i+CD]==s[lst+CD]&&i+CD<=n&&lst+CD<=n) CD++;
        height[rnk[i]] = CD;
    }
    //height保存rank i 和 rank i-1之间的LCP
    //那么对于LCP(i,j) = min:height[k] k (rnk[i]<k<=rnk[j]]
}
int main() {
    scanf("%s",&s[1]);
    n = strlen(s+1);
    suffixsort();
    for(int i=1;i<=n;i++) {
        printf("%d ",sa[i]);
    }
    puts("");
    for(int i=2;i<=n;i++) {
        printf("%d ",height[i]);
    }
    puts("");
}
posted @ 2019-01-26 15:06  Newuser233  阅读(7)  评论(0)    收藏  举报