这题暴力就是两个串分别枚举点\(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; }