抄(yyb)代码真是开心的一批
这道题看上去确实是没有什么思路
之后想一想大概是在(parent)树上从儿子向父亲转移
但是好像不太对的样子
于是考虑在(parent)树上从父亲向儿子转移
显然父亲一定是儿子的一个后缀,于是父亲肯定在儿子里出现了一次
至于如何保证其出现第二次呢,我们可以用线段树合并来维护
用线段树合并来维护一下(endpos)集合,看一下父亲有没有在儿子里出现过两次就好了
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define re register
#define maxn 400005
#define M 8000005
#define LL long long
#define inf 999999999
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
char S[maxn];
int fa[maxn],len[maxn],son[maxn][26],rt[maxn],top[maxn],pos[maxn],dp[maxn];
int tax[maxn],A[maxn];
int l[M],r[M],d[M];
int n,tot,lst=1,cnt=1,ans=1;
int change(int now,int x,int y,int pos)
{
if(!now) now=++tot;d[now]++;
if(x==y) return now;
int mid=x+y>>1;
if(pos<=mid) l[now]=change(l[now],x,mid,pos);
else r[now]=change(r[now],mid+1,y,pos);
return now;
}
int merge(int a,int b,int x,int y)
{
if(!a) return b;if(!b) return a;
int root=++tot;
if(x==y) {d[root]=d[a]+d[b];return root;}
int mid=x+y>>1;
l[root]=merge(l[a],l[b],x,mid);r[root]=merge(r[a],r[b],mid+1,y);
d[root]=d[l[root]]+d[r[root]];
return root;
}
inline void ins(int c,int o)
{
int p=++cnt,f=lst; lst=p;
len[p]=len[f]+1,rt[p]=change(rt[p],1,n,o),pos[p]=o;
while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
if(!f) {fa[p]=1;return;}
int x=son[f][c];
if(len[f]+1==len[x]) {fa[p]=x;return;}
int y=++cnt;
len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
for(re int i=0;i<26;i++) son[y][i]=son[x][i];
while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
int query(int now,int x,int y,int lx,int ry)
{
if(!now) return 0;
if(lx<=x&&ry>=y) return d[now]>0;
int mid=x+y>>1;
if(ry<=mid) return query(l[now],x,mid,lx,ry);
if(lx>mid) return query(r[now],mid+1,y,lx,ry);
return query(l[now],x,mid,lx,ry)|query(r[now],mid+1,y,lx,ry);
}
int main()
{
scanf("%d",&n);scanf("%s",S+1);
for(re int i=1;i<=n;i++) ins(S[i]-'a',i);
for(re int i=1;i<=cnt;i++) tax[len[i]]++;
for(re int i=1;i<=n;i++) tax[i]+=tax[i-1];
for(re int i=1;i<=cnt;i++) A[tax[len[i]]--]=i;
for(re int i=cnt;i>1;--i)
rt[fa[A[i]]]=merge(rt[fa[A[i]]],rt[A[i]],1,n),pos[fa[A[i]]]=max(pos[fa[A[i]]],pos[A[i]]);
for(re int i=2;i<=cnt;i++)
{
int x=A[i];
if(fa[x]==1) {dp[x]=1;top[x]=x;continue;}
int now=query(rt[top[fa[x]]],1,n,pos[x]-len[x]+len[top[fa[x]]],pos[x]-1);
if(now) dp[x]=dp[fa[x]]+1,top[x]=x;
else dp[x]=dp[fa[x]],top[x]=top[fa[x]];
ans=max(ans,dp[x]);
}
printf("%d
",ans);
return 0;
}