点击查看折叠代码块
/*
Str :需要处理的字符串(长度为Len)
Suffix[i] :Str下标为i ~ Len的连续子串(即后缀)
Rank[i] : Suffix[i]在所有后缀中的排名
SA[i] : 满足Suffix[SA[1]] < Suffix[SA[2]] …… < Suffix[SA[Len]],即排名为i的后缀为Suffix[SA[i]] (与Rank是互逆运算)
最长公共前缀(Longest Common Prefix,LCP)
Heigth[i] : 表示Suffix[SA[i]]和Suffix[SA[i - 1]]的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀
H[i] : 等于Height[Rank[i]],也就是后缀Suffix[i]和它前一名的后缀的最长公共前缀
而两个排名不相邻的最长公共前缀定义为排名在它们之间的Height的最小值。
*/
const int N = 1e5+10;
const int D = 18;
int t1[N],t2[N],c[N],lg2[N];
struct suffix_array{
int str[N],sa[N],rank[N],height[N];
int rmq[D][N];
bool cmp(int *r,int a,int b,int l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int n,int m){
n++; int i, j, p, *x = t1, *y = t2;
for(i=0;i<m;++i) c[i]=0;
for(i=0;i<n;++i) c[x[i]=str[i]]++;
for(i=1;i<m;++i) c[i]+=c[i-1];
for(i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
for(j=1;j<n;j<<=1){
p=0;
for(i=n-j;i<n;++i) y[p++]=i;
for(i=0;i<n;++i) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<m;++i) c[i]=0;
for(i=0;i<n;++i) c[x[y[i]]]++;
for(i=1;i<m;++i) c[i]+=c[i-1];
for(i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y); p=1; x[sa[0]]=0;
for(i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
if(p>=n) break; m=p;
}
int k=0; n--;
for(i=0;i<=n;++i) rank[sa[i]]=i;
for(i=0;i<n;++i){
if(k) k--;
j=sa[rank[i]-1];
while(str[i+k]==str[j+k]) ++k;
height[rank[i]]=k;
}
}
void initlcp(int n){
for(int i=1;i<=n;++i)
rmq[0][i]=height[i];
for(int k=1;k<=lg2[n];++k)//做倍增
for(int i=1;i+(1<<k)-1<=n;++i)
rmq[k][i]=min(rmq[k-1][i],rmq[k-1][i+(1<<(k-1))]);
}
int lcp(int a,int b){
a=rank[a]; b=rank[b];
if(a>b) swap(a,b); a+=1;
int d=lg2[b-a+1];
return min(rmq[d][a],rmq[d][b-(1<<d)+1]);
}
}sa;
char s[N]; int n;
int p[N][3],f[3];
bool cmp(int a,int b){
for(int i=0,l,l1,l2;i<3;++i){
if(p[a][i]==n) return true;
if(p[b][i]==n) return false;
l1=p[a][i+1]-p[a][i]-1; l2=p[b][i+1]-p[b][i]-1;
if(l1==0&&l2==0) continue;
else if(l1==0) return true;
else if(l2==0) return false;
l=sa.lcp(p[a][i]+1,p[b][i]+1);
if(l==min(l1,l2)){
if(l1==l2) continue;
else return l1<l2;
}else return sa.str[p[a][i]+1+l]<sa.str[p[b][i]+1+l];
}
return false;
}
lg2[0]=-1;
for(int i=1;i<N;++i) lg2[i]=(i&(i-1))?lg2[i-1]:lg2[i-1]+1;//预处理log