给你多个串找到最长公共字串
对第一个串建树
然后维护所有串在每一个节点处最小的匹配值
然后遍历所有节点找到最大
需要注意的是需要从最长的后缀开始往前遍历 如果当前节点被匹配到了 那么它的父亲节点一定也被匹配到了 而且是匹配到了父亲节点的长度 (因为子节点最短的后缀也比父亲节点最长的后缀长)
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 400000+100;
char s[maxn];
struct node{
int ch[26];
int len,fa;
node(){
memset(ch,0,sizeof(ch));
len = fa = 0;
}
}dian[maxn];
int tot = 1,las = 1;
void add(int c){
int p = las;
int np = las = ++tot;
dian[np].len =dian[p].len+1;
for(;p&&!dian[p].ch[c];p = dian[p].fa)dian[p].ch[c] = np;
if(!p)dian[np].fa = 1;
else{
int q = dian[p].ch[c];
if(dian[q].len==dian[p].len+1){
dian[np].fa = q;
}
else{
int nq = ++tot;
dian[nq] = dian[q];
dian[nq].len = dian[p].len+1;
dian[q].fa = dian[np].fa = nq;
for(;p&&dian[p].ch[c]==q;p = dian[p].fa)dian[p].ch[c] = nq;
}
}
}
int mn[2000000];
int l[2000000];
int arr[2000000];
int x[2000000];
int main(){
int flag = 0;memset(mn,0,sizeof(mn));
// memset(vis,0,sizeof(vis));
int cnt = 0;
while(scanf("%s",s)!=EOF){
int len =strlen(s);
cnt++;
if(!flag){
for(int i = 0;i<len;++i){
add(s[i]-'a');
}
for(int i = 1;i<=tot;++i){
l[i] = dian[i].len;
}
flag = 1;
//x数组计算长度排名为1-tot对应的节点下标 要从长度最长的后缀向前回溯
for(int i = 1;i<=tot;++i){
mn[l[i]]++;
}
for(int i = 1;i<=len;++i){
mn[i]+=mn[i-1];
}
for(int i = 1;i<=tot;++i){
x[mn[l[i]]--]=i;
}
for(int i = 1;i<=tot;++i){
mn[i] = l[i];
}
}
else{
int p = 1;
int t = 0;
memset(arr,0,sizeof(arr));
for(int i = 0;i<len;++i){
int c = s[i]-'a';
if(dian[p].ch[c]){
p = dian[p].ch[c];
t++;
arr[p] = max(t,arr[p]);
}
else{
for(;p&&!dian[p].ch[c];p = dian[p].fa);
if(!p){
p = 1;
t = 0;
}
else{
t = dian[p].len+1;
p = dian[p].ch[c];
arr[p] = max(arr[p],t);
}
}
}
for(int i = tot;i>=1;--i){//从长度排名为tot的串开始往前拓扑
int t = x[i];
//cout<<i<<" "<<mn[i]<<" "<<arr[i]<<endl;
mn[t] = min(mn[t],arr[t]);
if(mn[t]&&dian[t].fa){
arr[dian[t].fa] = l[dian[t].fa];
}
arr[t] = 0;
}
}
}
int ans = 0;
for(int p = tot;p>=1;--p){
ans = max(ans,mn[p]);
}
cout<<ans<<endl;
}