CF700E Cool Slogans

题目

(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;
}
原文地址:https://www.cnblogs.com/asuldb/p/10333849.html