【Luogu】P3809后缀排序(后缀数组模板)

  题目链接

  今天终于学会了后缀数组模板qwq

  不过只会模板emmmm

  首先我们有一本蓝书emmmmmm

  然后看到蓝书221页代码之后我就看不懂了

  于是请出rqy

  rqy:

  一开始那是个对单个字符排序的操作啊

  c[i]表示值为i的字符有多少个

  x[i]表示第i个位置的优先级是多少

  sa[i]表示优先级是i的字符位置

  然后第一行明显是初始化,第二行明显就是统计字符个数

  至于第三行为什么要求前缀和呢

  我们思考优先级越小的排的越靠前

  所以说,设优先级是0的有c[0]个,优先级是1的有c[1]个,以此类推

  所以说我们有c[0]个字符假设是'0',应该排到[ 0,c[0] )区间左闭右开

  然后截下来有c[1]个字符假设是'1',应该排到[ c[0],c[0]+c[1] )区间左闭右开

  然后以此类推

  所以我们简记一下c的前缀和,记为S

  于是我们排序的区间就变成了[0,S[0])  [S[0],S[1])   [S[1],S[2])

  等等等等。

  然后就可以愉快的基数排序啦

  然后考虑我们怎么搞两个关键字的排序

  就是我先把第二关键字排上,然后保证排序算法稳定的情况下排第一关键字

  第二关键字我可以直接枚举排。第一关键字……基数排序可以搞定qwq。

  然后看相邻的两个后缀编号是否相等,如果相等说明没能把它们区分开,接着排,如果不相等就可以退出了。

  

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cstdlib>
#define maxn 2000100
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

char s[maxn];
int sa[maxn];
int x[maxn];
int y[maxn];
int c[maxn];
int len;

void build(int m){
    for(int i=0;i<=m;++i)    c[i]=0;
    for(int i=1;i<=len;++i)    c[x[i]=s[i]]++;
    for(int i=1;i<=m;++i)    c[i]+=c[i-1];
    for(int i=len;i>=1;--i)    sa[c[x[i]]--]=i;
    for(int k=1;k<=len;k<<=1){
        int p=0;
        for(int i=len-k+1;i<=len;++i)    y[++p]=i;
        for(int i=1;i<=len;++i)
            if(sa[i]>k)        y[++p]=sa[i]-k;
        for(int i=0;i<=m;++i)    c[i]=0;
        for(int i=1;i<=len;++i)    c[x[y[i]]]++;
        for(int i=1;i<=m;++i)    c[i]+=c[i-1];
        for(int i=len;i>=1;--i)    sa[c[x[y[i]]]--]=y[i];
        std::swap(x,y);
        p=1;    x[sa[1]]=1;
        for(int i=2;i<=len;++i)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p:++p;
        if(p>=len)    break;
        m=p;
    }
}

int main(){
    scanf("%s",s+1);
    len=strlen(s+1);
    build(200);
    for(int i=1;i<=len;++i)    printf("%d ",sa[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/8277739.html