这题暴力就是两个串分别枚举点\(i,j\),假设这两个点不同,那么剩下的部分就是尽量越长越好,所以这部分答案就是第一个串\(i-1\)前缀和第二个串\(j-1\)前缀的\(lcs\)+第一个串\(i+1\)后缀和第二个串\(j+1\)后缀的\(lcp\)+1
考虑把两个串接起来,中间用个没用过的字符隔开,那么两个串前缀的\(lcs\)就可以先在前缀树上找到对应的两个点,然后就是两点\(lca\)的\(length\).后缀的\(lcp\)也类似.那么答案就是\(\max (lcs(a_{i-1},a_{j-1})+lcp(b_{i+1},b_{j+1}))\),其中\(a_i\)为某前缀在前缀树上对应点,\(b_i\)为后缀在后缀树上对应点
所以这个问题变成了询问所有点对在两棵树上lca深度和的最大值.可以dfs第一棵树,然后处理第一棵树上lca为\(x\)的点对,每次把儿子内点在第二棵树的信息合并过来,就能求解.首先,两个子树合并,为了保证复杂度,需要启发式合并,然后在合并时算贡献.现在就是要知道某个点和一个点集内点在第二棵树上的lca最大深度,容易发现一定和dfs序相邻的点lca最深.所以一个点维护的是子树内点在第二棵树上以dfs序为关键字的set,每次二分查找前驱后继即可
#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double
using namespace std;
const int N=2e5+10;
LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
struct SAM
{
int fa[N<<1],ch[N<<1][28],len[N<<1],la,tt;
int ps[N],px[N<<1],sz[N<<1],de[N<<1],hs[N<<1],top[N<<1],dfn[N<<1],ti;
vector<int> e[N<<1];
SAM(){la=tt=1;}
void extd(int cx,int ii)
{
int np=++tt,p=la;
len[np]=len[p]+1,ps[ii]=np,px[np]=ii,la=np;
while(!ch[p][cx]) ch[p][cx]=np,p=fa[p];
if(!p) fa[np]=1;
else
{
int q=ch[p][cx];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tt;
fa[nq]=fa[q],len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[np]=fa[q]=nq;
while(ch[p][cx]==q) ch[p][cx]=nq,p=fa[p];
}
}
}
void dfs1(int x)
{
sz[x]=1;
vector<int>::iterator it;
for(it=e[x].begin();it!=e[x].end();++it)
{
int y=*it;
de[y]=de[x]+1,dfs1(y);
sz[x]+=sz[y],hs[x]=sz[hs[x]]>sz[y]?hs[x]:y;
}
}
void dfs2(int x,int ntp)
{
dfn[x]=++ti,top[x]=ntp;
if(hs[x]) dfs2(hs[x],ntp);
vector<int>::iterator it;
for(it=e[x].begin();it!=e[x].end();++it)
{
int y=*it;
if(y==hs[x]) continue;
dfs2(y,y);
}
}
void inii()
{
for(int i=2;i<=tt;++i) e[fa[i]].push_back(i);
dfs1(1),dfs2(1,1);
}
int glca(int x,int y)
{
while(top[x]!=top[y])
{
if(de[top[x]]<de[top[y]]) swap(x,y);
x=fa[top[x]];
}
return de[x]<de[y]?x:y;
}
}t1,t2;
int n,m,ans;
char cc[N];
struct node
{
int x;
bool operator < (const node &bb) const {return t2.dfn[x]<t2.dfn[bb.x];}
};
multiset<node> s1[N<<1],s2[N<<1];
multiset<node>::iterator i1,i2,ft,nt,zr;
int id[N<<1],tot;
void dfs(int x)
{
vector<int>::iterator it;
id[x]=x;
if(t1.px[x])
{
if(t1.px[x]+1<=n+1) s1[id[x]].insert((node){t2.ps[t1.px[x]+2]});
else if(t1.px[x]+1>n+2&&t1.px[x]+2<=n+m+2) s2[id[x]].insert((node){t2.ps[t1.px[x]+2]});
}
for(it=t1.e[x].begin();it!=t1.e[x].end();++it)
{
int y=*it;
dfs(y);
if(s1[id[x]].size()+s2[id[x]].size()<s1[id[y]].size()+s2[id[y]].size()) swap(id[x],id[y]);
bool fg1=!s1[id[x]].empty(),fg2=!s2[id[x]].empty();
if(fg2)
{
for(i1=s1[id[y]].begin();i1!=s1[id[y]].end();++i1)
{
int xx=(*i1).x;
nt=s2[id[x]].upper_bound(*i1);
if(nt!=s2[id[x]].begin()) ft=--nt,++nt;
else ft=zr;
if((*ft).x) ans=max(ans,t1.len[x]+t2.len[t2.glca((*ft).x,xx)]+1);
if(nt!=s2[id[x]].end()) ans=max(ans,t1.len[x]+t2.len[t2.glca((*nt).x,xx)]+1);
}
}
if(fg1)
{
for(i2=s2[id[y]].begin();i2!=s2[id[y]].end();++i2)
{
int xx=(*i2).x;
nt=s1[id[x]].upper_bound(*i2);
if(nt!=s1[id[x]].begin()) ft=--nt,++nt;
else ft=zr;
if((*ft).x) ans=max(ans,t1.len[x]+t2.len[t2.glca((*ft).x,xx)]+1);
if(nt!=s1[id[x]].end()) ans=max(ans,t1.len[x]+t2.len[t2.glca((*nt).x,xx)]+1);
}
}
for(i1=s1[id[y]].begin();i1!=s1[id[y]].end();++i1) s1[id[x]].insert(*i1);
for(i2=s2[id[y]].begin();i2!=s2[id[y]].end();++i2) s2[id[x]].insert(*i2);
}
}
int main()
{
cc[1]='|';
scanf("%s",cc+2);
n=strlen(cc+2);
cc[n+2]='{';
scanf("%s",cc+n+3);
m=strlen(cc+n+3);
for(int i=1;i<=n+m+2;++i) t1.extd(cc[i]-'a',i);
t1.inii();
for(int i=n+m+2;i;--i) t2.extd(cc[i]-'a',i);
t2.inii();
s1[0].insert((node){0});
zr=s1[0].begin();
dfs(1);
printf("%d\n",ans);
return 0;
}