後綴數組(一)



o(︶︿︶)o 唉,也是爲了應付知識儲備太少,萬一遇到了類似的題不知道用啥算法就蛋疼了,所以來惡補一下這些東西。

囤一發模板,詳細講解請見2009羅橞騫的論文《後綴數組--處理字符串的有力工具》,基本網上所有的講解都是來自這篇文章,代碼也是這篇論文上的,就不說啥了。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
char s[MAXN];
int A[MAXN];
//爲了方便基數排序,我們把s中的字符轉換成數字.s和A的下標使用統一0-n-1 
int sa[MAXN],rank[MAXN];//最後結果的rank和sa
int Count[MAXN];//基數排序計數器 
int l[MAXN],r[MAXN],tmp[MAXN];//基數排序共有兩個關鍵字,r爲第二關鍵字基數排序結果,l值即臨時rank值. 
int n,maxn;//計數上界 
bool comp(int *A,int a,int b,int len)//字符串比較 
{
    return A[a]==A[b]&&A[a+len]==A[b+len];
}
int main()
{
    /*省略讀入等奇怪的過程*/
    int i,j,k,*x=l,*y=r;//後面會整體交換l,r爲了方便使用指針 
    for (i=0;i<maxn;i++)    Count[i]=0;
    for (i=0;i<n;i++)   Count[x[i]=A[i]]++;//第一次基數排序 
    for (i=1;i<maxn;i++)    Count[i]+=Count[i-1];
    for (i=n-1;i>=0;i--)    sa[--Count[x[i]]]=i;//初始的sa 
    for (k=1,i=1;i<n;k<<=1,maxn=i)
    {
        for (i=0,j=n-i;j<n;j++) y[i++]=i;//第二次基數排序
        for (j=0;j<n;j++)   if (sa[j]>=k)   y[i++]=sa[j]-k;
        for (j=0;j<n;j++)   tmp[j]=x[y[j]];
        for (j=0;j<maxn;j++)    Count[j]=0;
        for (j=0;j<n;j++)   Count[tmp[j]]++;
        for (j=1;j<maxn;j++)    Count[j]+=Count[j-1];
        for (j=n-1;j>=0;j--)    sa[--Count[tmp[j]]]=y[j];//更新sa 
        for (swap(x,y),i=1,x[sa[0]]=0,j=1;j<n;j++)  x[sa[j]]=comp(y,sa[j-1],sa[j],k)?i-1:i++;//更新rank
        //在更新過程中可能有兩字符串rank值相同,此時比較兩字符串是否完全相同來區分rank值
        //由於y數組在被用來更新sa後已經無用(下一次會重新求),節省空間使用y保存rank 
    }
}


o(︶︿︶)o 唉,也是爲了應付知識儲備太少,萬一遇到了類似的題不知道用啥算法就蛋疼了,所以來惡補一下這些東西。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章