SA后缀数组
需要再多去理解
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<ctime> 5 #include<iostream> 6 #include<algorithm> 7 #include<queue> 8 #include<set> 9 #define inf (0x7fffffff) 10 #define l(a) ((a)<<1) 11 #define r(a) ((a)<<1|1) 12 #define b(a) (1<<(a)) 13 #define rep(i,a,b) ;for(int i=a;i<=(b);i++) 14 #define clr(a) memset(a,0,sizeof(a)) 15 typedef long long ll; 16 typedef unsigned long long ull; 17 using namespace std; 18 int readint(){ 19 int t=0,f=1;char c=getchar(); 20 while(!isdigit(c)){ 21 if(c=='-') f=-1; 22 c=getchar(); 23 } 24 while(isdigit(c)){ 25 t=(t<<3)+(t<<1)+c-'0'; 26 c=getchar(); 27 } 28 return t*f; 29 } 30 const int maxn=2000009; 31 int n,m=256,mn=maxn,sa1[maxn],a[maxn],sum[maxn],sa[maxn],rank[maxn],height[maxn];//sa与rank意义相反 32 char s[maxn]; 33 void cal_SA(){ 34 clr(sum); 35 rep(i,1,n) sum[rank[i]=s[i]]++;//求初始rank 36 rep(i,1,m) sum[i]+=sum[i-1]; 37 for(int i=n;i;i--) sa[sum[rank[i]]--]=i;///基数排序求初始sa 注意这个奇妙的操作! 38 for(int l=1;l<n;l<<=1){ 39 //printf("rank==");rep(i,1,n) printf("%d ",rank[i]);puts(""); 40 //printf("sa==");rep(i,1,n) printf("%d ",sa[i]);puts(""); 41 42 int cnt=0; 43 rep(i,n-l+1,n) sa1[++cnt]=i;//后面的第二关键字为最小 44 rep(i,1,n) if(sa[i]>l) sa1[++cnt]=sa[i]-l;//利用sa对第二关键字的排序(sa1即第二关键字的sa) 45 46 //printf("sa1==");rep(i,1,n) printf("%d ",sa1[i]);puts(""); 47 48 rep(i,1,n) a[i]=rank[sa1[i]];//a为按第二关键字排序后的rank 注意! 49 50 //printf("a==");rep(i,1,n) printf("%d ",a[i]);puts(""); 51 52 clr(sum);rep(i,1,n) sum[a[i]]++; 53 rep(i,1,n) sum[i]+=sum[i-1]; 54 for(int i=n;i;i--) sa[sum[a[i]]--]=sa1[i];//求出新的sa 55 //综合第一关键字对a排序 和上面类似的奇妙操作(a按第二关键字排序了,所以这样倒着统计即可) 56 57 //printf("sa==");rep(i,1,n) printf("%d ",sa[i]);puts(""); 58 59 cnt=0; 60 rep(i,1,n) a[i]=rank[i];//将rank的值保存出来 61 rep(i,1,n){ 62 rank[sa[i]]=(a[sa[i-1]]==a[sa[i]]&&a[sa[i-1]+l]==a[sa[i]+l])?cnt:++cnt; 63 }//计算出新的rank 此处要利用rank考虑字符串相同的情况 64 65 //printf("rank==");rep(i,1,n) printf("%d ",rank[i]);puts(""); 66 //puts(""); 67 68 if(cnt==n) break;//cnt==n即排序完成 69 } 70 /*rep(i,1,n){ 71 printf("%d",rank[i]); 72 putchar(i==n?'\n':' '); 73 }*/ 74 rep(i,1,n){ 75 printf("%d",sa[i]); 76 putchar(i==n?'\n':' '); 77 } 78 } 79 void cal_Height(){//height[i]=suffix(sa[i-1])和suffix(sa[i])的最大公共前缀 80 //suffix(i)和suffix(j)的最大公共前缀为min(height[rank[i]+1],height[rank[i]+2]...height[rank[j]]) 81 int k=0; 82 rep(i,1,n){ 83 if(k) k--; 84 int j=sa[rank[i]-1]; 85 while(s[i+k]==s[j+k]) k++; 86 height[rank[i]]=k; 87 }//利用h数组(h[i]=height[rank[i]])的性质(h[i]>=h[i-1]-1)(可证)计算height 88 rep(i,2,n){ 89 printf("%d",height[i]); 90 putchar(i==n?'\n':' '); 91 } 92 } 93 void init(){ 94 scanf("%s",s+1);n=strlen(s+1); 95 rep(i,1,n) sum[int(s[i])]=1; 96 rep(i,1,m) sum[i]+=sum[i-1]; 97 rep(i,1,n) s[i]=sum[s[i]-1]+1;//将字符串转变为从1开始的整数 98 } 99 int main(){ 100 //freopen("#input.txt","r",stdin); 101 //freopen("#output.txt","w",stdout); 102 init(); 103 cal_SA(); 104 cal_Height(); 105 //fclose(stdin); 106 //fclose(stdout); 107 return 0; 108 }