F10【模板】后缀数组(SA)

视频链接:610 后缀数组(SA)_哔哩哔哩_bilibili

 

Luogu P3809 【模板】后缀排序

// Luogu P3809 【模板】后缀排序
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int N=2000010;
char s[N];
int n,m;//n为后缀个数, m为桶的个数
int x[N],y[N],c[N],sa[N],rk[N],height[N];
//桶数组x[i],辅助数组y[i],计数数组c[i]
void get_sa(){
  int i,j,k;
  //按第一个字母排序
  for(i=1;i<=n;i++)c[x[i]=s[i]]++;
  for(i=1;i<=m;i++)c[i]+=c[i-1];
  for(i=n;i;i--)sa[c[x[i]]--]=i;
  for(k=1;k<=n;k<<=1){ //logn轮
    //按第二关键字排序
    memset(c,0,sizeof(c));
    for(i=1;i<=n;i++)y[i]=sa[i];
    for(i=1;i<=n;i++)c[x[y[i]+k]]++;
    for(i=1;i<=m;i++)c[i]+=c[i-1];
    for(i=n;i;i--)sa[c[x[y[i]+k]]--]=y[i];
    //按第一关键字排序
    memset(c,0,sizeof(c));
    for(i=1;i<=n;i++)y[i]=sa[i];
    for(i=1;i<=n;i++)c[x[y[i]]]++;
    for(i=1;i<=m;i++)c[i]+=c[i-1];
    for(i=n;i;i--)sa[c[x[y[i]]]--]=y[i];
    //把后缀放入桶数组
    for(i=1;i<=n;i++)y[i]=x[i];
    for(m=0,i=1;i<=n;i++)
      if(y[sa[i]]==y[sa[i-1]]&&
        y[sa[i]+k]==y[sa[i-1]+k])x[sa[i]]=m;
      else x[sa[i]]=++m;
    if(m==n)break;//已排好    
  }  
}
void get_height(){
  int i,j,k;
  for(i=1;i<=n;i++)rk[sa[i]]=i;
  for(i=1,k=0;i<=n;i++){ //枚举后缀i
    if(rk[i]==1)continue;//第一名height为0
    if(k)k--;//上一个后缀的height值减1
    int j=sa[rk[i]-1];//找出后缀i的前邻后缀j
    while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
    height[rk[i]]=k;
  }
}
int main(){
  scanf("%s",s+1);
  n=strlen(s+1); m=122;
  get_sa();
  get_height();
  for(int i=1;i<=n;i++)printf("%d ",sa[i]);
  // puts("");
  // for(int i=1;i<=n;i++)printf("%d ",height[i]);
  return 0;
}

 

posted @ 2022-04-16 09:48  董晓  阅读(677)  评论(1编辑  收藏  举报