P3809 【模板】后缀排序

学完后缀数组后第一个模板题

后缀中:

sa[i]  : 开头为i的后缀

rak[i]:排名为i的后缀的开头位置

#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAXN = 1e6 + 10;
using namespace std;
char s[MAXN];
int N, M, rak[MAXN], sa[MAXN], tax[MAXN], tp[MAXN];
//tp[i]   第二关键字排名i的下标
//rak[i]  第一关键字排名i的下标。。最终是排名i的后缀的下标
//sa[i]   下标i的后缀的排名 
void Debug() {
    printf("*****************\n");
    printf("下标"); for (int i = 1; i <= N; i++) printf("%d ", i);     printf("\n");
    printf("sa  "); for (int i = 1; i <= N; i++) printf("%d ", sa[i]); printf("\n");
    printf("rak "); for (int i = 1; i <= N; i++) printf("%d ", rak[i]); printf("\n");
    printf("tp  "); for (int i = 1; i <= N; i++) printf("%d ", tp[i]); printf("\n");
}
void Qsort() {
    for (int i = 0; i <= M; i++) tax[i] = 0;
    for (int i = 1; i <= N; i++) tax[rak[i]]++;
    for (int i = 1; i <= M; i++) tax[i] += tax[i - 1];
    for (int i = N; i >= 1; i--) sa[ tax[rak[tp[i]]]-- ] = tp[i];
    //基数排序,sa[tax[z]--]=tp[i],更新排名
	//z是第二关键字排名i的后缀	放在什么位置。  tax[z]是第一关键字排名一样的放在一起 
}
void SuffixSort() {
    M = 75;
    for (int i = 1; i <= N; i++) rak[i] = s[i] - '0' + 1, tp[i] = i;
    Qsort();
  //  Debug();
    for (int w = 1, p = 0; p < N; M = p, w <<= 1) {
        //w:当前倍增的长度,w = x表示已经求出了长度为x的后缀的排名,现在要更新长度为2x的后缀的排名
        //p表示不同的后缀的个数,很显然原字符串的后缀都是不同的,因此p = N时可以退出循环
        p = 0;//这里的p仅仅是一个计数器000
        for (int i = N; i >= N-w+1; i--) tp[++p] = i;
//这里一直没看懂,其实就是后面的字符串后W是空的  所以优先级更高而已。 
        for (int i = 1; i <= N; i++) if (sa[i] > w) tp[++p] = sa[i] - w; 
//这里就是利用上一次求的长度w后缀的排名,这次的tp是后w,即i+w位置的rak所以从排名前的往后找,找的优先级一定更高 
     /*   puts("-----"); 
        puts("-----"); 
		Debug();
        puts("-----"); 
        puts("-----"); */
		Qsort();//此时我们已经更新出了第二关键字,利用上一轮的rak更新本轮的sa
        swap(tp, rak);//这里原本tp已经没有用了
        rak[sa[1]] = p = 1;
        for (int i = 2; i <= N; i++)
            rak[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
        //判断合并后的后缀的前缀是否完全相同。相同就在rak里相同 
	  //  Debug();
    }
    for (int i = 1; i <= N; i++)
        printf("%d ", sa[i]);
}
int main() {
    scanf("%s", s + 1);
    N = strlen(s + 1);
    SuffixSort();
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章