紫书习题的代码,虽然能ac,但是板子有问题,如果输入就会错,我在别的博客修改了板子戳我传送,这里懒得改了(毕竟紫书的板子只要输入的字符串的字符种类大于1就不会错)。
78ms代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=200005;                    //字符串的长度
char s[MAXN];                            //输入字符串
int sa[MAXN],cnt[MAXN],t1[MAXN],t2[MAXN],rk[MAXN],height[MAXN];
int n;

void calc_sa(){                                //n是字符串长度 
    int m=127;                                //m是小写字母的ASCII码值范围,构成字符串s的后缀数组,每个字符的值必须为0~m-1
    int i,*x=t1,*y=t2;
    for(i=0;i<m;i++)    cnt[i]=0;
    for(i=0;i<n;i++)    cnt[x[i]=s[i]]++;
    for(i=1;i<m;i++)    cnt[i]+=cnt[i-1];
    for(i=n-1;i>=0;i--)    sa[--cnt[x[i]]]=i;
    //sa[]:从0到n-1
    for(int k=1;k<=n;k*=2){                    //利用对长度为k的排序结果对长度为2k的排序 
        int p=0;
        //2nd
        for(i=n-k;i<n;i++)    y[p++]=i;
        for(i=0;i<n;i++)    if(sa[i]>=k)    y[p++]=sa[i]-k;
        //1st
        for(i=0;i<m;i++)    cnt[i]=0;
        for(i=0;i<n;i++)    cnt[x[y[i]]]++;
        for(i=1;i<m;i++)    cnt[i]+=cnt[i-1];
        for(i=n-1;i>=0;i--)    sa[--cnt[x[y[i]]]]=y[i];
        swap(x,y);
        p=1; x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)    break;
        m=p;
    } 
}
void getheight(){                        //n是字符串长度 
    int i,j,k=0;
    for(i=0;i<n;i++)    rk[sa[i]]=i;    //用sa[]推导rk[] 
    for(i=0;i<n;i++){
        if(k)    k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])    k++;
        height[rk[i]]=k;
    }
}
int main(){
    int len1,ans;
    while(scanf("%s",s)!=EOF){
        n=strlen(s);
        len1=n;
        s[n]='$';
        scanf("%s",s+n+1);
        n=strlen(s);
        calc_sa();
        getheight();
        ans=0;
        for(int i=1;i<n;i++)
            if(height[i]>ans&&((sa[i-1]<len1&&sa[i]>=len1)||(sa[i-1]>=len1&&sa[i]<len1)))
                ans=height[i];
        printf("%d\n",ans);
    }
    return 0;
}

800ms代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=200005;                    //字符串的长度
char s[MAXN];                            //输入字符串
int sa[MAXN],rk[MAXN],tmp[MAXN+1],height[MAXN];
int n,k;

/*比较函数
每一步使得 sa[]从0到n-1对应的字符串(从sa[i]开始的字串)按照组合数大小从小到大排序
最后一步使得sa[]从0到n-1对应的字符串(从sa[i]开始的字串)按照字典序从小到大排列*/
bool comp_sa(int i,int j){                //组合数有两个部分,高位是rk[i],低位是rk[i+k]
    if(rk[i]!=rk[j])                    //先比较高位:rk[i]和rk[j]
        return rk[i]<rk[j];
    else{                                //高位相等,再比较低位的rk[i+k]和rk[j+k]
        int ri = i+k<=n? rk[i+k] : -1;
        int rj = j+k<=n? rk[j+k] : -1;
        return ri<rj;
    }
}
void calc_sa(){                            //计算字符串s的后缀数组
    for(int i=0;i<=n;i++){
        rk[i]=s[i];                        //字符串的原始数值
        sa[i]=i;                        //后缀数组,在每一步记录当前排序后的结果
    }
    for(k=1;k<=n;k*=2){                    //开始一步步操作,每一步递增两倍进行组合
        sort(sa,sa+n,comp_sa);            //排序,结果记录在sa[]中(根据rk[]值的大小(各个字串的大小)从小到大将rk[]的下标(从第几个字符开始的)存在sa[]中)
        tmp[sa[0]]=0;                    //rk[sa[i]]=i;
        for(int i=0;i<n;i++)            //用sa[]倒推组合数,并记录在tmp[]中,用于临时存放rk[]的新值
            tmp[sa[i+1]]= tmp[sa[i]] + (comp_sa(sa[i],sa[i+1])?1:0);        //(排序后sa[i+1]大于或等于sa[i])
        for(int i=0;i<n;i++)            //把tmp[]复制给rk[],用于下一步操作
            rk[i] = tmp[i];                //每一步改变最高位 ,最后一步得到每个字串的排名
    }
}
void getheight(){                        //n是字符串长度 
    int i,j,k=0;
    for(i=0;i<n;i++){
        if(k)    k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])    k++;
        height[rk[i]]=k;
    }
}
int main(){
    int len1,ans;
    while(scanf("%s",s)!=EOF){
        n=strlen(s);
        len1=n;
        s[n]='$';
        scanf("%s",s+n+1);
        n=strlen(s);
        calc_sa();
        getheight();
        ans=0;
        for(int i=1;i<n;i++)
            if(height[i]>ans&&((sa[i-1]<len1&&sa[i]>=len1)||(sa[i-1]>=len1&&sa[i]<len1)))
                ans=height[i];
        printf("%d\n",ans);
    }
    return 0;
}