【模版】后缀数组(洛谷P3809)
洛谷上的模版题
模版的代码到处都是
模版各种详细的注释也到处都有
我偏偏看不懂
他们说要理解代码就要先学基数排序,我去学了,然后看懂了
回来理解后缀数组还是不会
听各种人给我讲每次都是一样的感觉,好像理解,突然又不会了
知道昨天早上LCA跟我语音终于把这个给讲明白了
最后发现问题还是处在基数排序
基数排序
这是一种稳定排序,就是这点让我纠结了两个月
稳定排序是在原先已经排好序的基础上的排序
换句话说,当遇到两个相同大小的元素出现时,要按照他们上一轮的大小排序
这就保证了后缀数组排序时第二关键字不需要单独拿出来重新排
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10000010
int c[300];
int t1[maxn],t2[maxn];
char str[maxn];
int sa[maxn];
void SA(int n){
int *x=t1,*y=t2,m=127;
for(int i=1;i<=m;++i) c[i]=0;
for(int i=1;i<=n;++i) c[x[i]=str[i]]++;
for(int i=1;i<=m;++i) c[i]+=c[i-1];
for(int i=n;i;--i) sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k+1;i<=n;++i) y[++p]=i;
for(int i=1;i<=n;++i) if(sa[i]>k) y[++p]=sa[i]-k;
for(int i=1;i<=m;++i) c[i]=0;
for(int i=1;i<=n;++i) c[x[y[i]]]++;
for(int i=1;i<=m;++i) c[i]+=c[i-1];
for(int i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
/*
问题基本就在上面3行,同样和倍增前求第一遍的时候都是基数排序
比较两段的区别基本上唯一的区别就在于i和y[i]
之前一直都没发现这一细节,今天一发现恍然大悟
倍增前的i是原序列没有排过的,要按照原来的位置排
现在的y[i]是上一轮排的结果向左移了k位,也就是第二关键字
重点就是基数排序在排的时候如果遇到相等不会损坏原有的第二关键字的顺序
*/
swap(x,y);
x[sa[1]]=1,p=1;
for(int i=2;i<=n;++i){
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]? p:++p;
}
m=p;
if(p>=n) break;
}
}
int main(){
scanf("%s",str+1);
int len=strlen(str+1);
SA(len);
for(int i=1;i<=len;++i){
printf("%d ",sa[i]);
}
return 0;
}