数据结构:后缀数组模板

点击查看折叠代码块
/*
Str :需要处理的字符串(长度为Len) 
Suffix[i] :Str下标为i ~ Len的连续子串(即后缀) 
Rank[i] : Suffix[i]在所有后缀中的排名 
SA[i] : 满足Suffix[SA[1]] < Suffix[SA[2]] …… < Suffix[SA[Len]],即排名为i的后缀为Suffix[SA[i]] (与Rank是互逆运算) 

最长公共前缀(Longest Common Prefix,LCP)
Heigth[i] : 表示Suffix[SA[i]]和Suffix[SA[i - 1]]的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀
H[i] : 等于Height[Rank[i]],也就是后缀Suffix[i]和它前一名的后缀的最长公共前缀 
而两个排名不相邻的最长公共前缀定义为排名在它们之间的Height的最小值。 
*/
const int N = 1e5+10;
const int D = 18;
int t1[N],t2[N],c[N],lg2[N];
struct suffix_array{
    int str[N],sa[N],rank[N],height[N];
    int rmq[D][N];
    bool cmp(int *r,int a,int b,int l){
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void da(int n,int m){
        n++; int i, j, p, *x = t1, *y = t2;
        for(i=0;i<m;++i) c[i]=0;
        for(i=0;i<n;++i) c[x[i]=str[i]]++;
        for(i=1;i<m;++i) c[i]+=c[i-1];
        for(i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
        for(j=1;j<n;j<<=1){
            p=0;
            for(i=n-j;i<n;++i) y[p++]=i;
            for(i=0;i<n;++i) if(sa[i]>=j) y[p++]=sa[i]-j;

            for(i=0;i<m;++i) c[i]=0;
            for(i=0;i<n;++i) c[x[y[i]]]++;
            for(i=1;i<m;++i) c[i]+=c[i-1];
            for(i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];

            swap(x,y); p=1; x[sa[0]]=0;
            for(i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
            if(p>=n) break; m=p;
        }
        int k=0; n--;
        for(i=0;i<=n;++i) rank[sa[i]]=i;
        for(i=0;i<n;++i){
            if(k) k--;
            j=sa[rank[i]-1];
            while(str[i+k]==str[j+k]) ++k;
            height[rank[i]]=k;
        }
    }
    void initlcp(int n){
        for(int i=1;i<=n;++i)
            rmq[0][i]=height[i];
        for(int k=1;k<=lg2[n];++k)//做倍增
            for(int i=1;i+(1<<k)-1<=n;++i)
                rmq[k][i]=min(rmq[k-1][i],rmq[k-1][i+(1<<(k-1))]);
    }
    int lcp(int a,int b){
        a=rank[a]; b=rank[b];
        if(a>b) swap(a,b); a+=1;
        int d=lg2[b-a+1];
        return min(rmq[d][a],rmq[d][b-(1<<d)+1]);
    }
}sa;
char s[N]; int n;
int p[N][3],f[3];
bool cmp(int a,int b){
    for(int i=0,l,l1,l2;i<3;++i){
        if(p[a][i]==n) return true;  
        if(p[b][i]==n) return false;
        l1=p[a][i+1]-p[a][i]-1; l2=p[b][i+1]-p[b][i]-1;
        if(l1==0&&l2==0) continue;
        else if(l1==0) return true;
        else if(l2==0) return false;
        l=sa.lcp(p[a][i]+1,p[b][i]+1);
        if(l==min(l1,l2)){
            if(l1==l2) continue;
            else return l1<l2;
        }else return sa.str[p[a][i]+1+l]<sa.str[p[b][i]+1+l];
    }
    return false;
}
lg2[0]=-1;
for(int i=1;i<N;++i) lg2[i]=(i&(i-1))?lg2[i-1]:lg2[i-1]+1;//预处理log
    
posted @ 2020-07-28 19:51  wsl_lld  阅读(67)  评论(0编辑  收藏  举报