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. FastDFS文件管理系统

    一.FastDFS介绍 FastDFS 是一个开源的高性能分布式文件系统(DFS). 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡.主要解决了海量数据存储问题,特别适合以中小文 ...

  2. 有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果

    问题:有一段<script>代码,效果是点击<p>就会弹出信息,但是有的<p>点击会有效果,有的没有效果 解决: 页面代码是至上而下执行的,如果你的这个标签在< ...

  3. Linux crontab 实现秒级定时任务

    1   crontab 的延时: 原理:通过延时方法 sleep N  来实现每N秒执行. crontab -e 输入以下语句,然后 :wq 保存退出. * * * * * /usr/bin/curl ...

  4. Hive 压缩技术Data Compression

    Mapreducwe 执行流程 :input > map > shuffle > reduce > output 压缩执行时间,map 之后,压缩,数据存储在本地磁盘,减少磁盘 ...

  5. Android开发——事件分发机制详解

    0. 前言   转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52566965 深入学习事件分发机制,是为了解决在Android开发中 ...

  6. Codeforces 787D Legacy 线段树 最短路

    题意: 有\(n(1 \leq n \leq 10^5)\)个点,\(q(1 \leq q \leq 10^5)\)条路和起点\(s\) 路有三种类型: 从点\(v\)到点\(u\)需要花费\(w\) ...

  7. 您的手机上未安装应用程序 android 点击快捷方式提示未安装程序的解决

    最近APP出现一个很奇怪的问题,在Android 4.4.2和android 4.4.3系统上点击应用的快捷方式,打不开应用,而且会提示未安装程序. 确认了应用的MainActivity中设置了and ...

  8. 线程间通信(等待,唤醒)&Java中sleep()和wait()比较

    1.什么是线程间通信? 多个线程在处理同一资源,但是任务却不同. 生活中栗子:有一堆煤,有2辆车往里面送煤,有2辆车往外拉煤,这个煤就是同一资源,送煤和拉煤就是任务不同. 2.等待/唤醒机制. 涉及的 ...

  9. sprintf()函数使用异常

    调试STM32F103,比如如下代码:使用springf函数,这个函数是把最后两个参数先格式化成字符串 ,输出到ERROR_STRING,如果他们合并的长度大于30会出现深情况? ] sprintf( ...

  10. loj2100 「TJOI2015」线性代数

    先推公式,推出个这,然后因为是 \(0/1\) 矩阵,选一个有损耗,两个一组有加成,就想到了最大权闭合子图,(飞行计划问题) #include <iostream> #include &l ...