后缀数组与LCP
后缀数组
首先,将一个字符串的所有后缀按字典序排序。
后缀数组 s a [ i ] sa[i] sa[i]:表示所有后缀在排完序后,排名为 i i i 的后缀在原串中的位置。
名次数组 r a n k [ i ] rank[i] rank[i]:表示所有后缀在排序完后,原字符串中第 i i i 名现在的排名。
显然, s a sa sa 与 r a n k rank rank 是互逆的,即 r a n k [ s a [ i ] ] = i , s a [ r a n k [ i ] ] = i ; rank[sa[i]]=i,sa[rank[i]]=i; rank[sa[i]]=i,sa[rank[i]]=i;
倍增求sa
我们求后缀的排名,可以每次求出区间 [ i , i [i,i [i,i+ 2 ∗ w 2∗w 2∗w− 1 ] 1] 1] 的排名, w w w= 1 , 2 , 4 , 8... 1,2,4,8... 1,2,4,8...求 [ i , i [i,i [i,i+ 2 ∗ w 2∗w 2∗w− 1 ] 1] 1] 的排名,我们可以将它分为 [ i , i [i,i [i,i+ w w w- 1 ] 1] 1] 和 [ i [i [i+ w , i w,i w,i+ 2 ∗ w 2∗w 2∗w− 1 ] 1] 1] 两部分。
所有可以以 [ i , i [i,i [i,i+ w w w- 1 ] 1] 1] 的排名为第一关键字, [ i [i [i+ w , i w,i w,i+ 2 ∗ w 2∗w 2∗w− 1 ] 1] 1]的排名为第二关键字,来对所有的 i i i 排序。
于是我们就可以用个 s o r t sort sort 在 O ( n l o g 2 n ) O(nlog^2 n) O(nlog2n) 内进行后缀排序了。
CODE
int rnk[N],sa[N],h[N];
struct p{
int a,b,id;
}p[N];
bool cmp(const P&a,const P&b){
return a.a==b.a?a.b<b.b:a.a<b.a;
}
int init_sa(char *s){
int n=std::strlen(s);
for(int i=0;i<n;i++) rnk[i]=s[i];
for(int i=1;i<n;i<<=1){
for(int j=0;j<n;j++)
p[j]=P{
rnk[j],j+1>=n?-1:rnk[j+1],j};
std::sort(p,p+n,cmp);
int c;
for(int j=0;j<n;j++){
rnk[p[j].id]=c;
c+=!(p[j].a==p[j+1].a&&p[j].b==p[j+1].b);
}
}
}
LCP(最长公共前缀)
LCP,即最长公共前缀,Longgest Common Prefix。
记 l c p ( i , j ) lcp(i,j) lcp(i,j) 表示 s a i sa_i sai 与 s a j sa_j saj 的最长公共前缀。
则对任意