题目大意
给出一个字符串,询问分别以x,y结尾的子串是原串的前缀有多少个,最长串有多长,一对组合以x,y结尾的子串必须一样。
解题思路
可以使用kmp,可以发现就是求fail树上的lca。
code
#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std ;
int const maxn=30000 ;
int n,m,fail[maxn+10 ],f[maxn+10 ],dep[maxn+10 ],father[maxn+10 ][20 ];
char s[maxn+10 ];
int main(){
freopen("d.in" ,"r" ,stdin);
freopen("d.out" ,"w" ,stdout);
scanf ("%s" ,s+1 );n=strlen (s+1 );
dep[1 ]=1 ;
fo(i,2 ,n){
for (fail[i]=fail[i-1 ];fail[i]&&(s[fail[i]+1 ]!=s[i]);fail[i]=fail[fail[i]]);
if (s[fail[i]+1 ]==s[i])fail[i]++;
if (fail[i])f[i]=f[fail[i]]+1 ;
father[i][0 ]=fail[i];
dep[i]=dep[fail[i]]+1 ;
}
fail[1 ]=1 ;
int tmp=log (n)/log (2 );
fo(j,1 ,tmp)
fo(i,1 ,n)
father[i][j]=father[father[i][j-1 ]][j-1 ];
scanf ("%d" ,&m);
fo(i,1 ,m){
int l,r;scanf ("%d%d" ,&l,&r);
if (dep[l]<dep[r])swap(l,r);int rr=r;
fd(j,tmp,0 )
if (dep[father[l][j]]>=dep[r])
l=father[l][j];
if (i==2132 ){
int bb;
bb++;
}
if (l==r){
printf ("%d %d\n" ,f[l]+1 ,l);
continue ;
}
fd(j,tmp,0 )
if (father[l][j]!=father[r][j]){
l=father[l][j];
r=father[r][j];
}
printf ("%d %d\n" ,f[father[l][0 ]]+(father[l][0 ]!=0 ),father[l][0 ]);
}
return 0 ;
}