1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| const int MAXN=400010; //以下为倍增算法求后缀数组 int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } /**< 传入参数:str,sa,len+1,ASCII_MAX+1 */ void da(const int r[],int sa[],int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i<m; i++) Ws[i]=0; for(i=0; i<n; i++) Ws[x[i]=r[i]]++;//以字符的ascii码为下标 for(i=1; i<m; i++) Ws[i]+=Ws[i-1]; for(i=n-1; i>=0; i--) sa[--Ws[x[i]]]=i; /*cout<<"SA"<<endl;; for(int i=0;i<n+1;i++)cout<<sa[i]<<' ';*/ for(j=1,p=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]]; for(i=0; i<m; i++) Ws[i]=0; for(i=0; i<n; i++) Ws[wv[i]]++; for(i=1; i<m; i++) Ws[i]+=Ws[i-1]; for(i=n-1; i>=0; i--) sa[--Ws[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return; } int sa[MAXN],Rank[MAXN],height[MAXN]; //求height数组 /**< str,sa,len */ void calheight(const char *r,int *sa,int n) { int i,j,k=0; for(i=1; i<=n; i++) Rank[sa[i]]=i; for(i=0; i<n; height[Rank[i++]]=k) for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++); // Unified 不要乱用,出来检查为了方便的时候 否则容易RE,WA // for(int i=n; i>=1; --i) ++sa[i],Rank[i]=Rank[i-1];
}
//求lcp(suffixal(i),suffixal(j))
int mm[MAXN],dp[MAXN][20]; void initrmq(int n,int b[]) { mm[0]=-1; for(int i=1; i<=n; i++) { mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; dp[i][0]=b[i]; } for(int j=1; j<=mm[n]; j++) for(int i=1; i+(1<<j)-1<=n; i++) dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); }
int lcp(int x,int y) { x=Rank[x],y=Rank[y]; if(x>y) swap(x,y); x++; int k=mm[y-x+1]; return min(dp[x][k],dp[y-(1<<k)+1][k]); }
char s[N]; int a[N];
int main(){ scanf("%s",s); int ls = strlen(s); for(int i=0;i<ls;i++) a[i]=s[i]-'a'+1; a[ls]=0;
da(a,sa,ls+1,30); calheight(a,sa,ls); initrmq(ls+1,height); return 0; }
|