• 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;
    }
    
  • 相关阅读:
    linux下最简单的端口转发工具
    FRP 简单入门安装配置教程
    Linux上创建SSH隧道
    微信公众平台 · 小程序文档
    windows 10
    高清方法生成缩略图函数
    用python的turtle画图
    python安装包下载
    nginx 报invalid pid number
    derby数据库windows自带的客户端
  • 原文地址:https://www.cnblogs.com/asuldb/p/10333849.html
Copyright © 2020-2023  润新知