SA 後綴數組

SA 後綴數組

首先必定要肯定\(SA\)是個什麼東西
\(SA[i]\)表示的是排名爲\(i\)的後綴是哪個
至於後綴\(i\)的排名是多少,那個是\(rank[i]\)數組


固然啦
最最最難懂的就是基數排序
要是不用基數排序,每次對於一個二元組直接\(sort\)一下
這樣的複雜度是\(O(nlog^2)\)spa

對於二元組的基數排序應該是這樣作的:
首先把全部元素按照最後一維丟到依次對應的桶裏面
而後順次取出
再按照第一維依次丟入
再順次取出
這樣就能夠排序啦code


先把代碼丟出來排序

bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
void GetSA()
{
    int m=30;
    for(int i=1;i<=n;++i)t[x[i]=a[i]]++;
    for(int i=1;i<=m;++i)t[i]+=t[i-1];
    for(int i=n;i>=1;--i)SA[t[x[i]]--]=i;
    for(int k=1;k<=n;k<<=1)
    {
        int p=0;
        for(int i=0;i<=m;++i)y[i]=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;
        for(int i=0;i<=m;++i)t[i]=0;
        for(int i=1;i<=n;++i)t[x[y[i]]]++;
        for(int i=1;i<=m;++i)t[i]+=t[i-1];
        for(int i=n;i>=1;--i)SA[t[x[y[i]]]--]=y[i];
        swap(x,y);
        x[SA[1]]=p=1;
        for(int i=2;i<=n;++i)x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
        if(p>=n)break;
        m=p;
    }
}

首先,第一次作\(k=0\)
至關於每一個後綴的第二維都是同樣的
因此,直接按照第一維(也就是本身的值)
進行一次基數排序class

接下來
每次基數排序都要利用到上一次的值sort

還記得吧,基數排序是先按照第二維從小往大拍
那麼,咱們就先把第二維的順序搞出來
首先最小的必定就是沒有第二維的東西
因此咱們先把這些數直接丟進數組裏面
接下來就是有第二維的東西啦
\(i\)位的第二維是啥?\(rank[i+k]\)
因此,從小到達枚舉\(SA\),這樣保證第二維從小往大
那麼,只要\(SA[i]>k\)
就證實它是一個東西的第二維
因此,把\(SA[i]-k\)丟到數組裏面去就好啦while

這樣的話,按照第二維就拍好啦
再來依次按照第一維丟到桶裏面去
作一遍基數排序就好啦
這樣就可以求出\(SA\)co

看起來很簡單誒。。
只是數組不要搞混了
必定搞清楚每一個數組是幹啥的
好比個人代碼
\(SA\)是後綴數組,\(SA[i]\)表示排名爲\(i\)的串是哪個
\(rank\)至關於排名,\(rank[i]\)表示第\(i\)個串的排名
\(x,y\)兩個數組是記錄順序的
分別記錄第一維和第二維的排序的順序
\(t\)是桶字典

這樣咱們就很愉快的求出了\(SA\)
還有一個數組\(Height\)
\(Height[i]\)表示串\(SA[i]\)\(SA[i-1]\)的最長公共前綴的長度
好比說,如今要求後綴\(i\)\(j\)的最長公共前綴
那就只須要求\(min(Height[i]),i \in [rank[i]+1,rank[j]]\)
由於已經按照字典序排好序啦block

\(Height\)顯然能夠暴力求
可是太不優美
咱們有\(Height[rank[i]]>=Height[rank[i-1]]-1\)
證實(來自\(hihoCoder\))

\(suffix(k)\)是排在\(suffix(i-1)\)前一名的後綴,
則它們的最長公共前綴是\(height[rank[i-1]]\)
那麼\(suffix(k+1)\)將排在\(suffix(i)\)的前面(這裏要求\(height[rank[i-1]]>1\),若是\(height[rank[i-1]]≤1\),原式顯然成立)
而且\(suffix(k+1)\)\(suffix(i)\)的最長公共前綴是\(height[rank[i-1]]-1\)
因此\(suffix(i)\)和在它前一名的後綴的最長公共前綴至少是\(height[rank[i-1]]-1\)

那麼,咱們按照\(rank\)的順序來求\(Height\)就行啦

for(int i=1;i<=n;++i)Rank[SA[i]]=i;
    for(int i=1,j=0;i<=n;++i)
    {
        if(j)j--;
        while(a[i+j]==a[SA[Rank[i]-1]+j])++j;
        height[Rank[i]]=j;
    }

我如今也不是很熟 之後多作點題我再接着補

相關文章
相關標籤/搜索