【Codeforces 700E】Cool Slogans(后缀自动机+线段树合并)
首先满足条件的一定是树上的一条链
然后就是要求一个在另一个里出现了两次
这个维护一下集合就可以判断了
从上往下递推找到最长的即可
有些细节可以见代码对克隆节点的处理
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define bg begin
cs int RLEN=(1<<20)+1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
template<class tp>inline void chemx(tp&a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp&a,tp b){a>b?a=b:0;}
cs int N=200005;
int n;
namespace Seg{
cs int N=::N<<6;
int lc[N],rc[N],siz[N],tot;
#define mid ((l+r)>>1)
inline int copy(int r1){
int u=++tot;lc[u]=lc[r1],rc[u]=rc[r1],siz[u]=siz[r1];return u;
}
void insert(int &u,int l,int r,int p){
u=copy(u);
siz[u]++;
if(l==r)return;
if(p<=mid)insert(lc[u],l,mid,p);
else insert(rc[u],mid+1,r,p);
}
void merge(int &u,int r1,int r2,int l,int r){
if(!r1||!r2){u=r1+r2;return;}
u=++tot,siz[u]=siz[r1]+siz[r2];
if(l==r)return;
merge(lc[u],lc[r1],lc[r2],l,mid);
merge(rc[u],rc[r1],rc[r2],mid+1,r);
}
int query(int u,int l,int r,int st,int des){
if(!u)return 0;
if(st<=l&&r<=des)return siz[u];
int res=0;
if(st<=mid)res+=query(lc[u],l,mid,st,des);
if(mid<des)res+=query(rc[u],mid+1,r,st,des);
return res;
}
#undef mid
}
namespace Sam{
cs int N=::N<<1;
int pos[N],fa[N],len[N],nxt[N][26],isc[N],tot=1,last=1;
inline void insert(int c,int ps){
int cur=++tot,p=last;len[cur]=len[p]+1;
last=cur,pos[cur]=ps;
for(;p&&!nxt[p][c];p=fa[p])nxt[p][c]=cur;
if(!p)fa[cur]=1;
else{
int q=nxt[p][c];
if(len[p]+1==len[q])fa[cur]=q;
else{
int clo=++tot;isc[clo]=1;
len[clo]=len[p]+1,fa[clo]=fa[q],pos[clo]=pos[q];
memcpy(nxt[clo],nxt[q],sizeof(nxt[q]));
for(;p&&nxt[p][c]==q;p=fa[p])nxt[p][c]=clo;
fa[q]=fa[cur]=clo;
}
}
}
int buc[N],rk[N],rt[N];
inline void radix_sort(){
for(int i=1;i<=tot;i++)buc[len[i]]++;
for(int i=1;i<=tot;i++)buc[i]+=buc[i-1];
for(int i=1;i<=tot;i++)rk[buc[len[i]]--]=i;
for(int i=tot;i>=1;i--){
int u=rk[i];
if(pos[u]&&!isc[u])Seg::insert(rt[u],1,n,pos[u]);
Seg::merge(rt[fa[u]],rt[fa[u]],rt[u],1,n);
}
}
int f[N],fr[N];
inline void solve(){
int mx=0;//cout<<tot<<'\n';
for(int i=1;i<=tot;i++){
int u=rk[i];
if(u==1)continue;
if(fa[u]==1){
f[u]=1,fr[u]=u;
}
else{
int p=fr[fa[u]];
if(Seg::query(rt[p],1,n,pos[u]-len[u]+len[p],pos[u])>1){
f[u]=f[fa[u]]+1,fr[u]=u;
}
else f[u]=f[fa[u]],fr[u]=p;
}
chemx(mx,f[u]);
}
cout<<mx<<'\n';
}
}
char s[N];
int main(){
#ifdef Stargazer
freopen("lx.cpp","r",stdin);
#endif
cin>>n;
scanf("%s",s+1);
for(int i=1;i<=n;i++)Sam::insert(s[i]-'a',i);
Sam::radix_sort();
Sam::solve();
}