后缀数组模板第一版
/*---------------倍增算法+RMQ后缀数组模板-------------- 输入:从0开始的字符串g,长度len最大为10^6 输出: sa[]表示:n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺 次放入 sa 中,sa[i]表示排第i位的字符串开头是sa[i],因为添加了一个结尾0,所以sa[0]=len height 数组(h[]):定义 h[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公 共前缀,也就是排名相邻的两个后缀的最长公共前缀。 mrank[i]表示:以i位开头的字符串,排名为mrank[i]。mrank[len]=0; cal(x,y):查询g[b]g[b+1]...g[len-1]与g[d]g[d+1]...g[len-1]的最大前缀数。 复杂度:空间复杂度33*len,时间复杂度,建立后缀数组为len*log(len),若不需要建立RMQ为len --------------------------------------------------*/ int r[N]; int sa[N]; int scnt[N]; int wa[N],wb[N],wv[N]; int mrank[N]; int h[N],th[N]; int rmqdp[N][22]; int savek[N]; int cmp(int gg[],int a,int b,int k) { return gg[a]==gg[b] && gg[a+k]==gg[b+k]; } void getsa(int str[],int sa[],int n,int m) { int i,*x,*y,*t; x=wa; y=wb; memset(scnt,0,sizeof(scnt)); for(i=0;i<n;i++) scnt[ x[i]=str[i] ]++; for(i=1;i<m;i++) scnt[i]+=scnt[i-1]; for(i=0;i<n;i++) sa[ --scnt[ str[i] ] ]=i; for(int p=1,j=1;p<n;j*=2,m=p) { for(p=0,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<n;i++) wv[i]=x[ y[i] ]; memset(scnt,0,sizeof(scnt)); for(i=0;i<n;i++) scnt[ wv[i] ]++; for(i=1;i<m;i++) scnt[i]+=scnt[i-1]; for(i=n-1;i>=0;i--) sa[ --scnt[ wv[i] ] ] = y[i]; for(p=1,t=x,x=y,y=t,x[sa[0]]=0,i=1;i<n;i++) x[ sa[i] ] = cmp(y,sa[i],sa[i-1],j)?p-1:p++; } } void geth(int str[],int n) { h[n-1]=0; int p=0; for(int i=0;i<n-1;i++) { int tmp=mrank[i]; while( str[i+p] == str[ sa[tmp-1]+p ] ) p++; h[i]=p; p--; p=max(0,p); } } void buildst(int n) { for(int i=1;i<=n;i++) rmqdp[i][0] = th[i]; for(int i=1;(1<<i)<=n;i++) { for(int j=1;j<=n;j++) { if( j+(1<<(i-1)) >n ) rmqdp[j][i]=rmqdp[j][i-1]; else rmqdp[j][i]=min(rmqdp[j][i-1],rmqdp[j+(1<<(i-1))][i-1]); } } } int cal(int x,int y) { x=mrank[x]; y=mrank[y]; if(x>y) swap(x,y); x++; //然后就是求x到y的最小值 int k = savek[y-x+1]; return min(rmqdp[x][k],rmqdp[y-(1<<k)+1][k]); } void SuffixInit(char gg[],int len) { //初始化RMQ中得k for(int i=1;i<N;i++) savek[i] = floor( log((double)i)/log(2.0) ); for(int i=0;i<len;i++) r[i]=gg[i]; r[len++]=0; getsa(r,sa,len,300); for(int i=0;i<len;i++) mrank[ sa[i] ]=i; //for(int i=0;i<len;i++) printf("%s\n",g+sa[i]); geth(r,len); for(int i=0;i<len-1;i++) th[ mrank[i] ]= h[i]; buildst(len-1); /* int b,d; while(scanf("%d%d",&b,&d)) { printf("%d\n",cal( b,d ));//查询g[b]g[b+1]...g[len-1]与g[d]g[d+1]...g[len-1]的最大前缀数。 } */ }
//求sa更快的3DC3 #define N 20020 #define F(x) ((x)/3+((x)%3==1?0:tb)) #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) int wa[N],wb[N],wv[N],mws[N]; char s[N]; int str[3*N]; int sa[3*N]; int mrank[N]; int h[N]; int c0(int *r,int a,int b) { return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2]; } int c12(int k,int *r,int a,int b) { if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1); else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1]; } void msort(int *r,int *a,int *b,int n,int m) { int i; for(i=0;i<n;i++) wv[i]=r[a[i]]; for(i=0;i<m;i++) mws[i]=0; for(i=0;i<n;i++) mws[wv[i]]++; for(i=1;i<m;i++) mws[i]+=mws[i-1]; for(i=n-1;i>=0;i--) b[--mws[wv[i]]]=a[i]; return; } void dc3(int *r,int *sa,int n,int m) { int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p; r[n]=r[n+1]=0; for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i; msort(r+2,wa,wb,tbc,m); msort(r+1,wb,wa,tbc,m); msort(r,wa,wb,tbc,m); for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++) rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++; if(p<tbc) dc3(rn,san,tbc,p); else for(i=0;i<tbc;i++) san[rn[i]]=i; for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3; if(n%3==1) wb[ta++]=n-1; msort(r,wb,wa,ta,m); for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i; for(i=0,j=0,p=0;i<ta && j<tbc;p++) sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++]; for(;i<ta;p++) sa[p]=wa[i++]; for(;j<tbc;p++) sa[p]=wb[j++]; return; } void geth(int str[],int n) { for(int i=0;i<n;i++) mrank[ sa[i] ]=i; h[n-1]=0; int p=0; for(int i=0;i<n-1;i++) { int tmp=mrank[i]; while( str[i+p] == str[ sa[tmp-1]+p ] ) p++; h[i]=p; p--; p=max(0,p); } } int main() { while(scanf("%s",s)) { int len=strlen(s); int n=0; for(int i=0;i<len;i++) str[n++]=s[i]; str[n++]=0; dc3(str,sa,n,256); geth(str,n); //已经得到h } return 0; }