[UOJ35]后缀排序
[UOJ35]后缀排序
题目大意:
对于给定的长度为\(n(n\le10^6)\)的字符串求后缀数组\(sa[i]\)和高度数组\(lcp[i]\)。
思路:
倍增+快排构造后缀数组,利用\(rank[i]\)求\(lcp[i]\)。时间复杂度\(\mathcal O(n\log^2 n)\)。
源代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=1e5+1;
char s[N];
int n,k,sa[N],rank[N],tmp[N],lcp[N];
inline bool cmp(const int &i,const int &j) {
if(rank[i]!=rank[j]) return rank[i]<rank[j];
const int ri=i+k<=n?rank[i+k]:-1;
const int rj=j+k<=n?rank[j+k]:-1;
return ri<rj;
}
inline void suffix_sort() {
for(register int i=0;i<=n;i++) {
sa[i]=i;
rank[i]=s[i];
}
for(k=1;k<=n;k<<=1) {
std::sort(&sa[0],&sa[n]+1,cmp);
tmp[sa[0]]=0;
for(register int i=1;i<=n;i++) {
tmp[sa[i]]=tmp[sa[i-1]]+!!cmp(sa[i-1],sa[i]);
}
std::copy(&tmp[0],&tmp[n]+1,rank);
}
}
inline void init_lcp() {
for(register int i=0,h=0;i<n;i++) {
if(h>0) h--;
const int j=sa[rank[i]-1];
while(j+h<n&&i+h<n&&s[j+h]==s[i+h]) h++;
lcp[rank[i]-1]=h;
}
}
int main() {
scanf("%s",s);
n=strlen(s);
suffix_sort();
init_lcp();
for(register int i=1;i<=n;i++) {
printf("%d%c",sa[i]+1," \n"[i==n]);
}
for(register int i=1;i<n;i++) {
printf("%d%c",lcp[i]," \n"[i==n-1]);
}
return 0;
}