Description

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

Solution

1A挺开心的省得调了
对于SAM上的每一个节点,我们只需要考虑right集合大小为1的
设一个right集合大小为1的点结束点在endpos,有效长度为[l,r]
那么对于区间[endpos-r+1,endpos-l+1],这个点的贡献为endpos-i+1,用一颗线段树维护endpos+1,i最后计算贡献
对于区间[endpos-l+1,endpos],这个点的贡献为l,再开一颗线段树维护l
最后扫一遍单点查询最小值就好了
标记永久化好像非常短还好写= =

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#define N (200000+1000)
using namespace std; char s[N];
int Ans,n; struct SGT
{
int Segt[N<<];
SGT(){memset(Segt,0x7f,sizeof(Segt));} void Update(int now,int l,int r,int l1,int r1,int k)
{
if (r<l1 || l>r1) return;
if (l1<=l && r<=r1){Segt[now]=min(Segt[now],k);return;}
int mid=(l+r)>>;
Update(now<<,l,mid,l1,r1,k); Update(now<<|,mid+,r,l1,r1,k);
}
void Query(int now,int l,int r,int x)
{
Ans=min(Ans,Segt[now]);
if (l==r) return;
int mid=(l+r)>>;
if (x<=mid) Query(now<<,l,mid,x);
else Query(now<<|,mid+,r,x);
}
}SGT[]; struct SAM
{
int fa[N],son[N][],right[N],step[N],End[N],od[N],wt[N];
int p,q,np,nq,last,cnt;
SAM(){last=++cnt;} void Insert(int x,int pos)
{
p=last; last=np=++cnt; step[np]=step[p]+; right[np]=; End[np]=pos;
while (p && !son[p][x]) son[p][x]=np,p=fa[p];
if (!p) fa[np]=;
else
{
q=son[p][x];
if (step[p]+==step[q]) fa[np]=q;
else
{
nq=++cnt; step[nq]=step[p]+;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
while (son[p][x]==q) son[p][x]=nq,p=fa[p];
}
}
}
void Init()
{
int len=strlen(s+);
for (int i=; i<=cnt; ++i) wt[step[i]]++;
for (int i=; i<=len; ++i) wt[i]+=wt[i-];
for (int i=cnt; i>=; --i) od[wt[step[i]]--]=i;
for (int i=cnt; i>=; --i) right[fa[od[i]]]+=right[od[i]];
}
void Solve()
{
for (int i=; i<=cnt; ++i)
if (right[i]==)
{
SGT[].Update(,,n,End[i]-step[i]+,End[i]-step[fa[i]],End[i]+);
SGT[].Update(,,n,End[i]-step[fa[i]],End[i],step[fa[i]]+);
}
for (int i=; i<=n; ++i)
{
Ans=0x7fffffff;
SGT[].Query(,,n,i); Ans-=i;
SGT[].Query(,,n,i);
printf("%d\n",Ans);
}
}
}SAM; int main()
{
scanf("%s",s+);
n=strlen(s+);
for (int i=; i<=n; ++i)
SAM.Insert(s[i]-'a',i);
SAM.Init();
SAM.Solve();
}

BZOJ1396:识别子串(SAM)的更多相关文章

  1. BZOJ1396 识别子串【SAM+SegmentTree】

    BZOJ1396 识别子串 给定一个串\(s\),对于串中的每个位置,输出经过这个位置且只在\(s\)中出现一次的子串的最短长度 朴素的想法是,我们要找到那些只出现一次的子串,之后遍历每个串,把串所覆 ...

  2. BZOJ-1396: 识别子串

    后缀自动机+线段树 先建出\(sam\),统计一遍每个点的\(right\)集合大小\(siz\),对于\(siz=1\)的点\(x\),他所代表的子串只会出现一次,设\(y=fa[x]\),则这个点 ...

  3. BZOJ1396 识别子串 和 BZOJ2865 字符串识别

    字符串识别 2865: 字符串识别 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 839  Solved: 261[Submit][Status][D ...

  4. bzoj千题计划318:bzoj1396: 识别子串(后缀自动机 + 线段树)

    https://www.lydsy.com/JudgeOnline/problem.php?id=1396 后缀自动机的parent树上,如果不是叶子节点,那么至少有两个子节点 而一个状态所代表子串的 ...

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

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

  6. BZOJ1396 识别子串 字符串 SAM 线段树

    原文链接http://www.cnblogs.com/zhouzhendong/p/9004467.html 题目传送门 - BZOJ1396 题意 给定一个字符串$s$,$|s|\leq 10^5$ ...

  7. bzoj1396识别子串(SAM+线段树)

    复习SAM板子啦!考前刷水有益身心健康当然这不是板子题/水题…… 很容易发现只在i位置出现的串一定是个前缀串.那么对答案的贡献分成两部分:一部分是len[x]-fa~len[x]的这部分贡献会是r-l ...

  8. BZOJ bzoj1396 识别子串

    题面: bzoj1396 题解: 先建出SAM,并计算right集合大小.显然符合条件的点的right集合大小为1. 对于每个right集合为1的状态显然可以算出这些状态的pos以及maxlen和mi ...

  9. bzoj1396: 识别子串

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

随机推荐

  1. access 2010,数学

    access 2010(窗体控制和创建窗体) 窗体向导:选择表格---创建---窗体---窗体向导---选择表/查询---全选可用字段---选择布局---设置标题---完成. 其他窗体:选择表格--- ...

  2. java——程序的导出与导入

    导出: 选择项目,右击选择 最下面的properties——Resource——Location,就是你的项目所在地, 找到文件所在,拷贝到你的U盘中(或者直接点击项目直接拖到桌面)完成复制 导入: ...

  3. vim的多标签

    vim支持多标签页,可以在同一窗口同时打开多个文档, 两种方法: vim -d 通过vim --help后发现vim -d相当与vimdiff模式 例子: $ vim -d a.txt b.txt c ...

  4. equals()重写

    ** 注意 ** 1.重写equals方法修饰符必须是public,因为是重写的Object的方法. 2.参数类型必须是Object. 3.重写equals方法后最好重写hashCode方法,否则两个 ...

  5. Oracle易忘知识点记录

    1.SQL Select语句完整的执行顺序: ①from子句组装来自不同数据源的数据: ②where子句基于指定的条件对记录行进行筛选: ③group by子句将数据划分为多个分组: ④使用聚集函数进 ...

  6. Python基础-列表生成式和生成器表达式

    一.列表生成式(List Comprehension) 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list ...

  7. 07_dubbo_compiler

    [开始解析最后一行代码 ExtensionLoader.getAdaptiveExtension()] ExtensionLoader<Protocol> loader = Extensi ...

  8. 139.00.005 Git学习-分支管理

    @(139 - Environment Settings | 环境配置) 一.Why? 分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交, ...

  9. Android Animation 知识点速记备忘思维导图

    备注的大段文本,无法在图片中体现, 思维导图源文件放在附件中.使用 Xmind 8 制作. 附件:AndroidAnimation-xmind.zip

  10. Python类型总结

    python 中处处是类的实例化 a=1 存储的是数字类型 而b='123'是字符串类型 []:读写方便的一张类型 True判断真假的一组{}键值对形式 class:则是描述静态元素和动态元素的结合体 ...