​LINK​

可以用 S A M SAM SAM预处理 r e s [ i ] res[i] res[i]表示以 i i i结尾的最大匹配长度

r e s [ i ] res[i] res[i]表示串 s [ 1... i ] s[1...i] s[1...i]与串 t t t的最长公共后缀

那么对于一个询问 [ l , r ] [l,r] [l,r]我们枚举终点位置.答案是

求 max ⁡ i = l r { min ⁡ ( i − l + 1 , r e s [ i ] ) } \max\limits_{i=l}^r\{\min(i-l+1,res[i])\} i=lmaxr{min(i−l+1,res[i])}的最大值

然后我就不会了…

主要是这个 m i n min min不好处理,但是我们可以分类讨论一下,当

r e s [ i ] < = i − l + 1 res[i]<=i-l+1 res[i]<=i−l+1时值为 r e s [ i ] res[i] res[i]

转化一下 i − r e s [ i ] + 1 > = l i-res[i]+1>=l i−res[i]+1>=l时值为 r e s [ i ] res[i] res[i]

发现 i − r e s [ i ] + 1 i-res[i]+1 i−res[i]+1是不减的,所以我们找到最小的点 p o s pos pos使得

p o s − r e s [ p o s ] + 1 > = l pos-res[pos]+1>=l pos−res[pos]+1>=l

那么 i ∈ [ l , p o s − 1 ] i\in[l,pos-1] i∈[l,pos−1]的贡献都是 i − l + 1 i-l+1 i−l+1,这部分最大值是 p o s − l pos-l pos−l

那么 i ∈ [ p o s , r ] i\in[pos,r] i∈[pos,r]的贡献都是 r e s [ i ] res[i] res[i],这部分可以用 S T ST ST表求

然后就可以了

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5+10;
int n,id=1,ed=1,len1,len2;
char a[maxn],b[maxn];
struct SAM
{
int zi[3],len,fa;
}sam[maxn]; int res[maxn][22];
void insert(int c)
{
int p = ed, np = ++id; ed = id;
sam[np].len = sam[p].len+1;
for( ;p&&!sam[p].zi[c];p=sam[p].fa ) sam[p].zi[c] = np;
if( p==0 ) sam[np].fa = 1;
else
{
int q = sam[p].zi[c];
if( sam[q].len==sam[p].len+1 ) sam[np].fa = q;
else
{
int nq = ++id;
sam[nq] = sam[q], sam[nq].len = sam[p].len+1;
sam[q].fa = sam[np].fa = nq;
for( ;p&&sam[p].zi[c]==q;p=sam[p].fa ) sam[p].zi[c] = nq;
}
}
}
void init()
{
cin >> ( a+1 ); len1 = strlen( a+1 );
cin >> ( b+1 ); len2 = strlen( b+1 );
for(int i=1;i<=len2;i++) insert( b[i]-'a' );
int p = 1, l = 0;
for(int i=1;i<=len1;i++)
{
int c = a[i]-'a';
if( sam[p].zi[c] ) l++,p = sam[p].zi[c];
else
{
while( p&&!sam[p].zi[c] ) p = sam[p].fa;
if( !p ) p = 1, l = 0;
else l = sam[p].len+1, p = sam[p].zi[c];
}
res[i][0] = l;
}
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<j)-1<=len1;i++)
res[i][j] = max( res[i][j-1],res[i+(1<<(j-1))][j-1] );
}
int getmax(int l,int r)
{
if( l>r ) return 0;
int k = log2(r-l+1);
return max( res[l][k],res[r-(1<<k)+1][k] );
}
int main()
{
init();
int q; cin >> q;
while( q-- )
{
int l,r; cin >> l >> r;
int L = l,R = r,pos = r+1;
while( R>=L )
{
int mid = L+R>>1;
if( mid-res[mid][0]+1>=l ) R = mid-1,pos = mid;
else L = mid+1;
}
cout << max( pos-l,getmax(pos,r) ) << endl;
}
}