题面: bzoj1396

题解:

先建出SAM,并计算right集合大小。显然符合条件的点的right集合大小为1.

对于每个right集合为1的状态显然可以算出这些状态的pos以及maxlen和minlen(fa的len+1)。

然后对于在pos和pos-minlen+1区间内的字符显然必须选长为minlen的一段区间。因此我们搞一棵线段树维护这些minlen,即对于在pos和pos-minlen+1区间内的字符在线段树上和minlen取min

对于另外的在pos-maxlen+1到pos-minlen+1的区间内,这些字符的区间长度都为\(pos-pos[i]\)(第二个pos[i]是每个字符的位置,第一个是该状态的pos),然后发现所有的这种情况都是\(pos\)减一个值,那么我们为了让其min,就另开一棵线段树维护每次pos的最小值。

最后统计答案即可。

#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (now<<1|1) using namespace std; namespace Tzh{ const int maxn=4e5+10;
const int inf=INT_MAX;
int tot=1,last=1,c[maxn],a[maxn];
string S; struct Suffix_AutoMaton{
int cnt,link,pos,len,ch[26];
}sam[maxn<<1]; struct segment_tree{ int ans[maxn]; struct Tr{
int lt,rt,tag;
}tree[maxn<<2]; void build(int now,int lt,int rt){
if(lt>rt) return ; tree[now].tag=inf;
tree[now].lt=lt,tree[now].rt=rt;
if(lt==rt) return ;
int mid=lt+rt>>1;
build(ls,lt,mid),build(rs,mid+1,rt);
} void change(int now,int lt,int rt,int w){
if(tree[now].rt<lt||tree[now].lt>rt) return;
if(tree[now].lt>=lt&&tree[now].rt<=rt)
tree[now].tag=min(tree[now].tag,w);
else change(ls,lt,rt,w),change(rs,lt,rt,w);
} void dfs(int now){
if(tree[now].lt==tree[now].rt){
ans[tree[now].lt]=tree[now].tag; return;
}
tree[ls].tag=min(tree[ls].tag,tree[now].tag);
tree[rs].tag=min(tree[rs].tag,tree[now].tag);
dfs(ls),dfs(rs);
} }seg1,seg2; void build(int x){ int cur=++tot,p=last;
sam[cur].len=sam[last].len+1; sam[cur].cnt=1;
sam[cur].pos=sam[cur].len-1; last=cur;
for(;p&&!sam[p].ch[x];p=sam[p].link) sam[p].ch[x]=cur;
if(!p) sam[cur].link=1;
else{ int q=sam[p].ch[x];
if(sam[q].len==sam[p].len+1) sam[cur].link=q;
else{ int clone=++tot;
sam[clone]=sam[q]; sam[clone].cnt=0;
sam[clone].len=sam[p].len+1;
for(;p&&sam[p].ch[x]==q;p=sam[p].link)
sam[p].ch[x]=clone;
sam[q].link=sam[cur].link=clone;
}
}
} void cal(){
for(int i=1;i<=tot;i++) c[sam[i].len]++;
for(int i=1;i<=tot;i++) c[i]+=c[i-1];
for(int i=1;i<=tot;i++) a[c[sam[i].len]--]=i;
for(int i=tot;i;i--){ int p=a[i];
sam[sam[p].link].cnt+=sam[p].cnt;
}
} void work(){
cin>>S;
for(int i=0;i<S.size();i++) build(S[i]-'a');
cal();seg1.build(1,0,S.size()),seg2.build(1,0,S.size());
for(int i=2;i<=tot;i++) if(sam[i].cnt==1){ int minlen=sam[sam[i].link].len+1;
seg1.change(1,sam[i].pos-minlen+1,sam[i].pos,minlen);
seg2.change(1,sam[i].pos-sam[i].len+1,sam[i].pos-minlen+1,sam[i].pos);
}
seg1.dfs(1),seg2.dfs(1);
for(int i=0;i<S.size();i++)
printf("%d\n",min(seg1.ans[i],seg2.ans[i]-i+1));
return ;
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("1396.in","r",stdin);
freopen("1396.out","w",stdout);
#endif
ios::sync_with_stdio(false);
Tzh::work();
return 0;
}

BZOJ bzoj1396 识别子串的更多相关文章

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

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

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

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

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

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

  4. BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)

    题目链接 SAM:能成为识别子串的只有那些|right|=1的节点代表的串. 设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-le ...

  5. BZOJ1396:识别子串(SAM)

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

  6. BZOJ-1396: 识别子串

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

  7. bzoj 1396 识别子串 后缀树+线段树

    题目大意 给定一个长度\(\le100000\)的字符串 求每一个位置的最短识别子串 对于位置\(x\),能识别子串\(s[i...j]\)的条件是 1.\(i\le x \le j\) 2.\(s[ ...

  8. BZOJ 1396:识别子串 SA+树状数组+单调队列

    1396: 识别子串 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 381  Solved: 243[Submit][Status][Discuss] ...

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

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

随机推荐

  1. 【Springboot】Springboot整合Thymeleaf模板引擎

    Thymeleaf Thymeleaf是跟Velocity.FreeMarker类似的模板引擎,它可以完全替代JSP,相较与其他的模板引擎,它主要有以下几个特点: 1. Thymeleaf在有网络和无 ...

  2. 为了约会,PM的领导能力篇来啦!

    之前我们花了很大力气阐述PM的过程能力成熟度,为的是让PM把项目管理得心应手,早点下班.可再完美的过程也要人来做啊!兄弟们要是不爽了,你还有心思约会么?那怎么才能管好组里的兄弟,让他们好好执行过程,早 ...

  3. PMM Client 安装异常报错

    1.PMM架构 如下图所示 2.Client主要组件 PMM Client是安装在你要监视的MySQL或MongoDB主机上的一组代理组件.组件收集关于一般系统和数据库性能的各种数据,并将该数据发送到 ...

  4. vue 导出xlsx表功能

    详细步骤: 1.需要安装三个依赖: npm install -S file-saver xlsx npm install -D script-loader 两个命令行包含三个依赖. 2.项目中src下 ...

  5. python 验证码识别库pytesseract的使用

    笔者环境 centos7 python3 pytesseract只是tesseract-ocr的一种实现接口.所以要先安装tesseract-ocr(大名鼎鼎的开源的OCR识别引擎). 依赖安装 yu ...

  6. About A Scam

    事件起因 本篇记录一个我遇到一个诈骗故事. 这两年我陆续有收到邮件,内容为有一大笔遗产我可以继承,让我提供银行卡号,身份证号相关信息. 后面邮件的内容就变为,有一笔公益款项,可以用我名义去管理,让我提 ...

  7. HTTPS中间人攻击实践(原理·实践)

      前言 很早以前看过HTTPS的介绍,并了解过TLS的相关细节,也相信使用HTTPS是相对安全可靠的.直到前段时间在验证https代理通道连接时,搭建了MITM环境,才发现事实并不是我想的那样.由于 ...

  8. .NET开源快速开发框架Colder发布 (NET452+AdminLTE版)

    .NET开源快速开发框架Colder(NET452+AdminLTE版) 引言 半年前将基于Easyui的快速开发框架开源,三个版本(NET4.52,NETCore和NET4.0)总共荣获200+星, ...

  9. python基础 常见用法

    1.python计时器timeit模块 1)timeit 模块定义了接收两个参数的Timer类,两个参数都是字符串. 参数1:要计时的语句或者函数 参数2:为参数1构建环境的导入语句 2)Timer对 ...

  10. MATLAB GUI界面设计------“轴”组件配置

    1> Fontsize            10         %字体大小 2> FontUnits           normalized      %采用相对度量单位,缩放时保持 ...