/*P1860 后缀数组
时间: 1000ms / 空间: 131072KiB / Java类名: Main
描述
我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串。
后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较
定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0
你的任务就是求出SA和height这两个数组。字符串长度<=200000
输入格式
一行,为描述中的字符串(仅会出现小写字母)
输出格式
共两行,每行n个数,第一行为sa[i],第二行为height[i],其中每行的数均用空格隔开
测试样例1
输入
aabaaaab
输出
4 5 6 1 7 2 8 3 
0 3 2 3 1 2 0 1*/
//本题算法就是题目名,而且还是后缀数组最简单的应用。
//关于后缀数组我不想多说,推荐  算法合集之《后缀数组——处理字符串的有力工具》此h非我代码中的h。
//有时真想有人给我讲讲,自学是非常非常痛苦的。
//但有2个点超时,不过不管了。
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 200008
using namespace std;
int n,sa[2][N],rk[2][N],a[N],v[N],k,h[N];
char ch[N];
void geng(int sa[N],int rk[N],int SA[N],int RK[N])
{
	for(int i=1;i<=n;i++)
	  v[rk[sa[i]]]=i;
	for(int i=n;i;i--)
	  if(sa[i]>k)
	    SA[v[rk[sa[i]-k]]--]=sa[i]-k;
    for(int i=n-k+1;i<=n;i++)
      SA[v[rk[i]]--]=i;
    for(int i=1;i<=n;i++)
      RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
    return;
}												
int main()
{
	gets(ch+1);
	n=strlen(ch+1);
	for(int i=1;i<=n;i++)
	  a[i]=ch[i]-'a'+1;
	int p=0,q=1;
	for(int i=1;i<=n;i++)
	  v[a[i]]++;
	for(int i=2;i<27;i++)
	  v[i]+=v[i-1];
	for(int i=1;i<=n;i++)
	  sa[p][v[a[i]]--]=i;
	for(int i=1;i<=n;i++)
	  rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
	for(k=1;k<n;k<<=1)
	  {
	  	geng(sa[p],rk[p],sa[q],rk[q]);
	  	swap(p,q);
	  }
	for(int i=1;i<=n;i++)
	  printf("%d ",sa[p][i]);
	printf("\n");
	k=0;
	for(int i=1;i<=n;i++)
	  if(rk[p][i]==1)
	  	h[1]=0;
	  else
	    {
	    	int j=sa[p][rk[p][i]-1];
	    	for(;a[i+k]==a[j+k];k++);
	    	h[rk[p][i]]=k;
	    	if(k>0)
	    	  k--;
		}
	for(int i=1;i<=n;i++)
	  printf("%d ",h[i]);	  
	return 0;
}
 
                    
                 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号