题解:
每次询问时对询问的两个串xx和yy分别做:
建后缀自动机,求出每个串是这个串的子串的最长前缀。
每个串对xx和yy的答案取min,所有串的答案取max即可。
时间复杂度O(nm)O(nm)
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
char ch[N];
int n,m,bg[N],ed[N],len;
int l[N*2],son[N*2][26],mx[N*2],ok[N*2],link[N*2],last,tot;
inline void sam_init() {
for(int i=1;i<=tot;i++)
memset(son[i],0,sizeof(son[i])), mx[i]=0, ok[i]=0;
last=tot=1;
}
inline void extend(int c) {
int p=++tot; l[p]=l[last]+1;
while(last && !son[last][c])
son[last][c]=p, last=link[last];
if(!last) link[p]=1;
else {
int q=son[last][c];
if(l[q]==l[last]+1) link[p]=q;
else {
int np=++tot; link[np]=link[q]; l[np]=l[last]+1;
memcpy(son[np],son[q],sizeof(son[np]));
link[q]=link[p]=np;
while(last && son[last][c]==q)
son[last][c]=np, last=link[last];
}
} last=p;
}
inline int upt_ok(int id) {
int p=1,i;
for(i=bg[id];i<=ed[id];i++) {
int c=ch[i]-'a';
if(!son[p][c]) break;
p=son[p][c]; ok[p]=1;
}
return i-bg[id];
}
int ans[N];
inline void solve() {
len=0; scanf("%d",&n);
for(int i=1;i<=n;i++) {
bg[i]=len+1;
scanf("%s",ch+bg[i]);
ed[i]=bg[i]+strlen(ch+bg[i])-1;
len=ed[i];
}
scanf("%d",&m);
for(int i=1;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
sam_init();
for(int j=bg[x];j<=ed[x];++j) extend(ch[j]-'a');
for(int j=1;j<=n;j++) ans[j]=upt_ok(j);
sam_init();
for(int j=bg[y];j<=ed[y];++j) extend(ch[j]-'a');
for(int j=1;j<=n;j++) ans[j]=min(ans[j],upt_ok(j));
int rs=0;
for(int j=1;j<=n;j++) rs=max(rs,ans[j]);
printf("%d\n",rs);
}
}
int main() {
int T; scanf("%d",&T);
l[0]=-1;
for(int i=0;i<26;i++)
son[0][i]=1;
while(T--) solve();
}