【模板】后缀数组
2017-01-24 17:50
211 查看
处理一个字符串中的所有后缀
应用:
-模式串匹配
-计算LCP(两个后缀之间的最长公共前缀)
应用:
-模式串匹配
-计算LCP(两个后缀之间的最长公共前缀)
#include <bits/stdc++.h> using namespace std; char s[1000003]; int len, cc[1000003], rank[1000003],//从第x位开始的后缀排第几 height[1000003],//跟排名前一位的字符串有多少相同 sa[1000003],//排名为x的字符串 t1[1000003],t2[1000003]; bool cmp(int *y,int a,int b,int k) { int arank1=y[a],brank1=y[b], arank2= a+k>=len ? -1:y[a+k], brank2= b+k>=len ? -1:y[b+k]; return arank1==brank1&&arank2==brank2; } void make_sa() { int *x=t1,*y=t2,m=26; for(int i=0;i<m;++i) cc[i]=0; for(int i=0;i<len;++i) ++cc[x[i]=s[i]-'a']; for(int i=1;i<m;++i) cc[i]+=cc[i-1]; for(int i=len-1;i>=0;--i) sa[--cc[x[i]]]=i; for(int k=1;k<=len;k<<=1) { int p=0; for(int i=len-k;i<len;++i) y[p++]=i; for(int i=0;i<len;++i) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;++i) cc[i]=0; for(int i=0;i<len;++i) ++cc[x[y[i]]]; for(int i=1;i<m;++i) cc[i]+=cc[i-1]; for(int i=len-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i]; swap(x,y); m=1; x[sa[0]]=0; for(int i=1;i<len;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1:m++; if(m>=len) break; } } void make_height() { for(int i=0;i<len;++i) rank[sa[i]]=i; height[0]=0; int k=0; for(int i=0;i<len;++i) { if(!rank[i]) continue; int j=sa[rank[i]-1]; if(k) --k; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } int main() { scanf("%s",&s); len=strlen(s); make_sa(); make_height(); // 以下为数组完成后的结果 for(int i=0;i<len;++i) printf("%s %d\n",s+sa[i],height[i]); printf("sa: "); for(int i=0;i<len;++i) printf("%d ",sa[i]); cout<<endl<<"rank: "; for(int i=0;i<len;++i) printf("%d ",rank[i]); cout<<endl; return 0; }//abccbab