Input

一行,一个由小写字母组成的字符串S,长度不超过10^5

Output

L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

Sample Input

agoodcookcooksgoodfood

Sample Output

1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
 
出现只有一次的是parent数上的叶子节点,endpos=1
所以只需要找endpos=1的节点minlen-maxlen之间对于一段的贡献放向去思考就可以了。
 

理解起来就是对于[endpos−maxlen+1,endpos−minlen+1][endpos−maxlen+1,endpos−minlen+1]中的每个子串都是单独存在的,所以这个RightRight集合贡献给他的答案就是这个点到endposendpos的长度。

对于[endpos−minlen,endpos][endpos−minlen,endpos]中的每个位置xx,贡献就是minlenminlen;

理解起来就是对于[endpos−minlen,endpos][endpos−minlen,endpos]中的每个子串显然是存在多个结束位置的,所以当前这个RightRight集合能够贡献给他的符合只出现一次且最短的,就是刚好跨过它的最小,即minlenminlen。

对于2865数据范围大了,而且还卡内存,不要面孔

纯自己手打

 #pragma GCC optimize(2)
#pragma G++ optimize(2)
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdio> #define inf 1000000007
#define N 200007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n;
char ch[N]; struct segment_tree
{
int tree[N<<];
inline void push_down(int p,int l,int r)
{
if(l==r)return;
int ls=p<<,rs=p<<|;
tree[ls]=min(tree[ls],tree[p]);
tree[rs]=min(tree[rs],tree[p]);
}
void update(int p,int l,int r,int x,int y,int num)
{
if(x>y)return;
push_down(p,l,r);
if(l==x&&y==r)
{
tree[p]=min(tree[p],num);
return;
}
int mid=(l+r)>>;
if(y<=mid)update(p<<,l,mid,x,y,num);
else if(x>mid)update(p<<|,mid+,r,x,y,num);
else update(p<<,l,mid,x,mid,num),update(p<<|,mid+,r,mid+,y,num);
}
void build(int p,int l,int r)
{
if(l==r)
{
tree[p]=inf;
return;
}
int mid=(l+r)>>;
build(p<<,l,mid),build(p<<|,mid+,r);
tree[p]=inf;
}
int query(int p,int l,int r,int x)
{
push_down(p,l,r);
if(l==r)return tree[p];
int mid=(l+r)>>;
if(x<=mid) return query(p<<,l,mid,x);
else return query(p<<|,mid+,r,x);
}
}A,B;
struct sam
{
int last,cnt,rt;
int fa[N],mx[N],c[N][];
sam(){last=cnt=rt=;}
void extend(int x)
{
int p=last,np=last=++cnt;mx[np]=mx[p]+;
while(p&&!c[p][x])
{
c[p][x]=np;
p=fa[p];
}
if(!p)fa[np]=rt;
else
{
int q=c[p][x];
if(mx[q]==mx[p]+)fa[np]=q;
else
{
int nq=++cnt;mx[nq]=mx[p]+;
memcpy(c[nq],c[q],sizeof(c[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
while(c[p][x]==q)c[p][x]=nq,p=fa[p];
}
}
}
bool flag[N];
void build()
{
memset(flag,true,sizeof(flag));
for (int i=;i<=cnt;i++)
flag[fa[i]]=false;
for (int i=;i<=cnt;i++)
if(flag[i])
{
int l=mx[i]-mx[fa[i]],r=mx[i];
A.update(,,n,,l-,r+);
B.update(,,n,l,r,r-l+);
}
}
}sam;
void solve()
{
for (int i=;i<=n;i++)
printf("%d\n",min(A.query(,,n,i)-i,B.query(,,n,i)));
}
int main()
{
freopen("fzy.in","r",stdin);
freopen("fzy.out","w",stdout);
scanf("%s",ch+);n=strlen(ch+);
for (int i=;i<=n;i++)
sam.extend(ch[i]-'a');
A.build(,,n),B.build(,,n);
// cout<<1<<endl<<endl;
sam.build(),solve();
}

bzoj1396&&2865 识别子串 后缀自动机+线段树的更多相关文章

  1. BZOJ 1396&&2865 识别子串[后缀自动机 线段树]

    Description 在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件: 1.i≤K≤j. 2.子串T只在S中出现过一次. 例如, ...

  2. 【BZOJ1396】识别子串 - 后缀自动机+线段树

    题意: Description Input 一行,一个由小写字母组成的字符串S,长度不超过10^5 Output L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. 题解: ...

  3. bzoj 1396/2865: 识别子串 后缀自动机+线段树

    水水的字符串题 ~ #include <map> #include <cstdio> #include <cstring> #include <algorit ...

  4. BZOJ1396: 识别子串(后缀自动机 线段树)

    题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...

  5. BZOJ 1396 识别子串 (后缀自动机+线段树)

    题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...

  6. BZOJ 1396: 识别子串( 后缀数组 + 线段树 )

    这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...

  7. 2018.12.23 bzoj2865&&1396: 字符串识别(后缀自动机+线段树)

    传送门 卡空间差评! 题意简述:给一个字串,对于每个位置求出经过这个位置且只在字串中出现一次的子串的长度的最小值. 解法:先建出samsamsam,显然只有当sizep=1size_p=1sizep​ ...

  8. bzoj千题计划319:bzoj2865: 字符串识别(后缀自动机 + 线段树)

    https://www.lydsy.com/JudgeOnline/problem.php?id=2865 同上一篇博客 就是卡卡空间,数组改成map #include<map> #inc ...

  9. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

随机推荐

  1. AWS CentOS7 实例修改主机名

    问题描述: AWS EC2 实例在升级到CentOS7以后,我们发现主机名的修改不再像之前的版本(CentOS 5/6)一样简单. 每次新建实例之后,修改好主机名,重启或者克隆之后的机器,主机名还是会 ...

  2. javascript常用代码片段

    /** * * @desc 判断两个数组是否相等 * @param {Array} arr1 * @param {Array} arr2 * @return {Boolean} */ function ...

  3. kali linux渗透系统的安装

    Kali 安装详细步骤   实验环境 Windows:Windows 10 企业版 VMware:VMware Workstation 12 Pro Kali:kali-linux-2016.2-am ...

  4. [Codeforces958C2]Encryption (medium)(区间DP)

    Description 题目链接 Solution 显然的区间DP,正常想法f[i][j]表示前i个数分成j块,每次在i前找一个k使得balala,然而常规打法会超时 我们发现,对于i前面的所有点,他 ...

  5. 十一、mysql老是停止运行该怎么解决

    mysql老是停止运行该怎么解决 你可能还会遇到无法启动mysql的错误 解决方法如下:      

  6. 2,版本控制git --分支

    有人把 Git 的分支模型称为它的`‘必杀技特性’',也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出. 为何 Git 的分支模型如此出众呢? Git 处理分支的方式可谓是难以置信的轻量, ...

  7. Eclipse 菜单---Eclipse教程第04课

    Eclipse 查看的菜单栏通常包含以下几个菜单: File 菜单 Edit 菜单 Navigate 菜单 Search 菜单 Project 菜单 Run 菜单 Window 菜单 Help 菜单 ...

  8. 用swoole实现nginx日志解析

    1.原技术路线解析 在nging配置中将日志信息交给syslog处理,rsyslog配置中将数据传递给了514端口解析,然后将解析好的数据传入elasticsearch中. nginx配置 serve ...

  9. 新工具填补Docker管理空白

    [TechTarget中国原创] 从事容器管理领域的IT运维专家这周需要评估一个新的工具. Docker推出了一款新产品,意在让IT运维人员能够跟上开发人员的脚步,这一产品是Docker Datace ...

  10. 剑指Offer - 九度1350 - 二叉树的深度

    剑指Offer - 九度1350 - 二叉树的深度2013-11-23 00:54 题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的 ...