以下模板单单注释了如何使用,算法详解可参考 罗穗骞《后缀数组——处理字符串的有力工具》
算法注释:
#include<cstdio>
#include<cstring>
#include<iostream>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;
const int maxn =
int s[maxn];
int sa[maxn],c[maxn],t[maxn],t2[maxn];
void build_sa(int m,int n) {
int i,*x=t,*y=t2;
//提前一次基数排序 将sa[]求出
//基数排序后满足x递增 当x相同时 按照i递增的顺序
//sa[i]在每次k循环完之后都保留着目前排名第i的是谁
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=s[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(int k=1;k<=n;k<<=1) {
//排序第二关键字
//根据已经算出的sa[]算出y[]
//y[i]中保存着谁的第二关键字排名第i (i的第二关键字为i+k)
int p=0;
for(i=n-k;i<n;i++) y[p++]=i; //第二关键字为0的排在前面
for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; //根据sa求出y
//排序第一关键字
//基数排序后满足x递增 当x相同时 按照y递增的顺序
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=0;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
//交换xy 并计算下一轮的x
//此时y中保存着原来的x 新的x是由排序产生的排名
swap(x,y);
p=1; x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
//若二元组的第一关键字与第二关键字相同的则名次相同
if(p>=n) break; //全部有序 即没有两个的名次是相等的 则停止倍增
m=p; //m<-总名次数
}
}
int rank[maxn],height[maxn];
void getHeight(int n) {
//H[i]=height[rank[i]]
//H[i]>=H[i-1]-1
int i,j,k=0;
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(s[j+k]==s[i+k]) k++;
height[rank[i]]=k;
}
}
使用注释:
#include<cstdio>
#include<cstring>
#include<iostream>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;
const int maxn = //长度范围
int s[maxn]; //字符串对应Ascii码 使用前可提前构造
int sa[maxn],c[maxn],t[maxn],t2[maxn];
//m代表字符最大值 n代表字符串长
//常常需要在字符串末尾加0以防止RE 令s[n]=0 调用build_sa(m,n+1)即可
void build_sa(int m,int n) {
int i,*x=t,*y=t2;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=s[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(int k=1;k<=n;k<<=1) {
int p=0;
for(i=n-k;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=0;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]]=y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p>=n) break;
m=p;
}
}
//n代表字符串长度
//调用getHeight(n)即可
int rank[maxn],height[maxn];
void getHeight(int n) {
int i,j,k=0;
for(i=0;i<=n;i++) rank[sa[i]]=i; //[0,n]
for(i=0;i<n;i++) { //不计算height[n] 即末尾0
if(k) k--;
j=sa[rank[i]-1];
while(s[j+k]==s[i+k]) k++;
height[rank[i]]=k;
}
}