定义:
先定义一个字符串s,假设它的长度为n,s[i]表示第i个元素 ,s[i...]代表以s[i]开头且包含s[i]的后缀。我们定义新的数组 sa[i]为一个0-n的排列,且sa[i]为后缀s[i...]在所有后缀中按 照从小到大排序的排名。最后定义rank是sa的反函数。
sa数组也称为后缀数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 struct  SA {    static  const  int  MAXN=2e5 +555 ;     static  int  lg[MAXN];     int  h[MAXN][20 ],rank[MAXN],sa[MAXN],n;     void  init (char *s,int  len)          static  int  x[MAXN],y[MAXN],c[MAXN];         n=len;         int  m=1000 ;         for (int  i=1 ;i<=n;i++)sa[i]=y[i]=0 ;         for (int  i=1 ;i<=n;i++)x[i]=s[i];         for (int  i=1 ;i<=m;i++)c[i]=0 ;         for (int  i=1 ;i<=n;i++)c[x[i]]++;         for (int  i=1 ;i<=m;i++)c[i]+=c[i-1 ];         for (int  i=n;i>=1 ;i--)sa[c[x[i]]--]=i;         for (int  k=1 ;k<=n;k<<=1 ){             int  num=0 ;             for (int  i=n-k+1 ;i<=n;i++)y[++num]=i;             for (int  i=1 ;i<=n;i++)if (sa[i]>k)y[++num]=sa[i]-k;             for (int  i=1 ;i<=m;i++)c[i]=0 ;             for (int  i=1 ;i<=n;i++)c[x[i]]++;             for (int  i=1 ;i<=m;i++)c[i]+=c[i-1 ];             for (int  i=n;i>=1 ;i--)sa[c[x[y[i]]]--]=y[i];             for (int  i=1 ;i<=n;i++)y[i]=x[i];             for (int  i=1 ;i<=n;i++)x[i]=0 ;             num=1 ;             x[sa[1 ]]=1 ;             for (int  i=2 ;i<=n;i++){                 if ((y[sa[i]]!=y[sa[i-1 ]])||(y[sa[i]+k]!=y[sa[i-1 ]+k])){                     x[sa[i]]=++num;                 }                 else  x[sa[i]]=num;             }             if (num>=n)break ;             m=num;         }         for (int  i=1 ;i<=n;i++)rank[i]=x[i];                  int  k=0 ;         for (int  i=1 ;i<=n;i++){             if (k)k--;             int  j=sa[rank[i]-1 ];             while ((i+k<=n)&&(j+k<=n)&&(s[i+k]==s[j+k]))k++;             h[rank[i]][0 ]=k;         }                  for (int  j=1 ;j<20 ;j++){             int  d=1 <<j;             for (int  i=1 ;i+2 *d-1 <=n;i++)h[i][j]=min (h[i][j-1 ],h[i+d][j-1 ]);         }         if (lg[1 ]!=0 )for (int  i=1 ;i<MAXN;i++)lg[i]=trunc (log (i+0.5 )/log (2 ));     }     int  lcp (int  x,int  y)          int  L=min (rank[x],rank[y])+1 ;         int  R=max (rank[x],rank[y]);         int  k=lg[R-L+1 ];         return  min (h[L][k],h[R-(1 <<k)+1 ][k]);     } }sa; int  SA::lg[SA::MAXN];