【後綴數組】後綴排序

最近幾天有很多題目沒有寫,儘量補上吧。

hz2016評測《《點擊訪問

caioj《《點擊訪問

後綴數組》後綴自動機

樹狀數組》線段樹

其實兩種都是用一個特殊的簡單結構,維護一部分高級算法的查詢結構。後綴自動機顧名思義,就是處理後綴的啦,這道題是模板題,把數組的所有後綴按照大到小排序。具體還是看代碼註釋吧,結合代碼會比較好理解。
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Maxchar 1524288 //1000000 +2^19
#define Maxs 30
#define mes(x,y) memset(x,y,sizeof(x));
#define mpy(x,y) memcpy(x,y,sizeof(x))
#define INF 2147483647
using namespace std;
int a[Maxchar+1],tt[Maxchar+1];
char s[Maxchar+1];
int Rank[Maxchar+1],sa1[Maxchar+1],Rank2[Maxchar+1],sa2[Maxchar+1],Rsort[Maxchar+1];
//Rank名次數組: 你排第幾?sa後綴數組:排第幾的是誰?(記錄是的起始位置) 後面的數字表示第幾關鍵字
void get_sa(int n,int m){
    memcpy(Rank,a,sizeof(Rank));
    //預處理第一關鍵字的排名:對長度爲1的字符串進行基數排序,求出sa 
    memset(Rsort,0,sizeof(Rsort));
    for(int i=1;i<=n;i++)Rsort[Rank[i]]++;
    for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
    for(int i=n;i>=1;i--)sa1[Rsort[Rank[i]]--]=i;
    int ln=1,p=0;//ln爲當前處理好的子串的長度,p表示有多少不相同的子串
    while(p<n){//現在處理的是長度爲ln*2的子串,開始將兩個關鍵字合併排序
    //爲啥不寫ln<=n?因爲有可能不需要排到ln=n就排完了,而當p==n就說明全部字符串不同,後面再也不會改變
        int k=0;//處理第二關鍵字的排名:
        for(int i=n-ln+1;i<=n;i++)sa2[++k]=i;//先把要補0的後綴處理好,他們肯定在前面 
        for(int i=1;i<=n;i++)if(sa1[i]-ln>0)sa2[++k]=sa1[i]-ln;
		//sa1[i]是sa1[i]-ln的第二關鍵字,因爲我們枚舉的是第二關鍵字的排名 
        //sa2記錄sa1[i]-ln的第二關鍵字的排名,指向sa1[i]-ln
        memset(Rsort,0,sizeof(Rsort));
        for(int i=1;i<=n;i++)Rsort[Rank[i]]++;
        for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1]; 
        for(int i=n;i>=1;i--)sa1[Rsort[Rank[sa2[i]]]--]=sa2[i];
        for(int i=1;i<=n;i++)tt[i]=Rank[i];//由於Rank會改變,判斷不了一、二關鍵字是否相等
        //用sa得到新的Rank數組,爲什麼預處理的時候不能求出Rank?因爲原來的Rank沒有兩個關鍵字
        p=1;Rank[sa1[1]]=1;
        for(int i=2;i<=n;i++){
            if(tt[sa1[i]]!=tt[sa1[i-1]]||tt[sa1[i]+ln]!=tt[sa1[i-1]+ln] )p++;
            //一二關鍵字其中一個不同,前後的字符串不同 
            Rank[sa1[i]]=p;
        } 
        m=p;ln*=2;
    }
} 
int main(){
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<=len;i++)a[i]=s[i]-'a'+1;
    get_sa(len,Maxs+1);
    for(int i=1;i<len;i++)printf("%d ",sa1[i]);printf("%d\n",sa1[len]);
    return 0;
}
具體就是這樣啦,大家趕快做題吧。

查看原文:http://hz2016.tk/blog/?p=28
發佈了127 篇原創文章 · 獲贊 52 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章