BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)
SAM:能成为识别子串的只有那些|right|=1的节点代表的串。
设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-len_{fa_i} ]\sim r_i\ ]\)这些子串都出现一次。
那么对于[ r[i]-len[i]+1, r[i]-len[fa[i]] ]都可以用此时对应的长度(r-i+1)更新其最小值(这个维护每个位置最小的r就可以)。
对于位置[ r[i]-len[fa[i]]+1, r[i] ]可以用len[fa[i]]+1更新(这个直接维护最小值)。
所以建两棵线段树就可以了。
SA:在整个串中不重复出现,我们能想到height。对于一个位置i,以它为左端点能形成的最短的不重复出现串长度l=max(ht[i],ht[i+1])+1.
那么i能对区间ii+l-2贡献l;包含i的子串长度>l时一定也只出现了一次,即可以对i+l-1n贡献对应长度(p-i+1)的值。还是用线段树维护。
l==r的时候不能PushDown啊mdzz。
//32176kb 928ms
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=1e5+5,INF=1061109554;
struct Segment_Tree
{
#define lson rt<<1
#define rson rt<<1|1
#define ToL l,m,rt<<1
#define ToR m+1,r,rt<<1|1
int mn[N<<2],tag[N<<2];
Segment_Tree(){
memset(mn,0x3f,sizeof mn), memset(tag,0x3f,sizeof tag);
}
inline void PushUp(int rt){
mn[rt]=std::min(mn[lson],mn[rson]);
}
inline void Update(int x,int v){
tag[x]=std::min(tag[x],v), mn[x]=std::min(mn[x],v);
}
inline void PushDown(int rt){
Update(lson,tag[rt]), Update(rson,tag[rt]), tag[rt]=INF;
}
void Modify(int l,int r,int rt,int L,int R,int v)
{//线段树都没一次写对→_→
if(L>R) return;
if(L<=l && r<=R){
tag[rt]=std::min(tag[rt],v), mn[rt]=std::min(mn[rt],v); return;
}
if(tag[rt]<INF) PushDown(rt);
int m=l+r>>1;
if(L<=m) Modify(ToL,L,R,v);
if(m<R) Modify(ToR,L,R,v);
// PushUp(rt);
}
}t1,t2;
struct Suffix_Automaton
{
#define S N<<1
int tot,las,fa[S],son[S][26],len[S],R[S],right[S],A[S],tm[S];
char s[N];
void Insert(int pos,int c)
{
int p=las,np=++tot;
len[las=np]=len[p]+1, R[np]=pos, right[np]=1;
for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
if(!p) fa[np]=1;
else
{
int q=son[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++tot; len[nq]=len[p]+1;
memcpy(son[nq],son[q],sizeof son[q]);
fa[nq]=fa[q], fa[q]=fa[np]=nq;
for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
}
}
}
int Build()
{
las=tot=1, scanf("%s",s+1);
int l=strlen(s+1);
for(int i=1; i<=l; ++i) Insert(i,s[i]-'a');
for(int i=1; i<=tot; ++i) ++tm[len[i]];
for(int i=1; i<=l; ++i) tm[i]+=tm[i-1];
for(int i=1; i<=tot; ++i) A[tm[len[i]]--]=i;
for(int i=tot,x=A[tot],f,p; i; x=A[--i])
{
right[fa[x]]+=right[x];// R[fa[x]]=R[x];
if(right[x]==1)
f=fa[x], p=R[x], t1.Modify(1,l,1,p-len[f]+1,p,len[f]+1), t2.Modify(1,l,1,p-len[x]+1,p-len[f],p);
}
return l;
}
}sam;
void Query(int l,int r,int rt)
{
if(l==r) printf("%d\n",std::min(t1.mn[rt],t2.mn[rt]-l+1));
else
{
if(t1.tag[rt]<INF) t1.PushDown(rt);
if(t2.tag[rt]<INF) t2.PushDown(rt);
Query(l,l+r>>1,rt<<1), Query((l+r>>1)+1,r,rt<<1|1);
}
}
int main()
{
int n=sam.Build(); Query(1,n,1);
return 0;
}
BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)的更多相关文章
- [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...
- 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并
题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...
- BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...
- BZOJ 1396:识别子串 SA+树状数组+单调队列
1396: 识别子串 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 381 Solved: 243[Submit][Status][Discuss] ...
- bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】
根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[ ...
- BZOJ 1396 识别子串 (后缀自动机、线段树)
手动博客搬家: 本文发表于20181221 00:58:26, 原地址https://blog.csdn.net/suncongbo/article/details/85150962 嗯,以后博客内容 ...
- BZOJ 1396 识别子串 (后缀自动机+线段树)
题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...
- bzoj 1396 识别子串 后缀树+线段树
题目大意 给定一个长度\(\le100000\)的字符串 求每一个位置的最短识别子串 对于位置\(x\),能识别子串\(s[i...j]\)的条件是 1.\(i\le x \le j\) 2.\(s[ ...
- ●BZOJ 1396 识别子串
题链: http://www.joyoi.cn/problem/tyvj-2301(非权限OI患者,苟且在joyoi...)题解: 后缀自动机,线段树 先对原串建立后缀自动机,不难发现, 会影响答案是 ...
随机推荐
- MySQL的备份和恢复-mysqldump
MySQL的备份和恢复-mysqldump 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.为什么需要备份 1>.做灾难恢复 天有不测风云嘛,如果你的服务器被黑客攻击了(比 ...
- Centos 7和 Centos 6开放查看端口 防火墙关闭打开
Centos 7 firewall 命令: 查看已经开放的端口: firewall-cmd --list-ports 开启端口 firewall-cmd --zone=public --add-por ...
- Redis记录-Redis高级应用
Redis数据库可以使用安全的方案,使得进行连接的任何客户端在执行命令之前都需要进行身份验证.要保护Redis安全,需要在配置文件中设置密码. 示例 下面的示例显示了保护Redis实例的步骤. 127 ...
- 20155318 2016-2017-2 《Java程序设计》第六周学习总结
20155318 2016-2017-2 <Java程序设计>第六周学习总结 教材学习内容总结 学习目标 理解流与IO 理解InputStream/OutPutStream的继承架构 理解 ...
- MFS - MooseFS 文件系统
MFSMooseFS 文件系统 可以实现RAID 功能:节约成本 实现在线扩展:是一种半分布式文件系统. 一.MFS文件系统的组成 1.mfsmaster 元数据服务器. 在整个体系中负责管理管理文件 ...
- 【IT界的厨子】家常版本的黄焖鸡
前言: 周末在家,闲来无事, 使用简单的食材,满足家人的味蕾,做出秒杀馆子的黄焖鸡(我是这么认为的).虽然没有厨师的手艺,但为家人做饭,也是一种幸福. 用料: 主料:老母鸡一只,要求店老板剁好 配料: ...
- Linux如何解决动态库的版本控制
引用自:http://www.linuxidc.com/Linux/2012-04/59071.htm (换句话说,soname不是真实存在的文件,只是在此库中和将来调用此库的文件中保存的一个名字,在 ...
- Gitlab的安装汉化及问题解决
Gitlab的安装汉化及问题解决(2017/12/14目前版本为10.2.4) 一.前言 Gitlab需要安装的包太TM多了,源码安装能愁死个人,一直出错,后来发现几行命令就装的真是遇到的新大陆一样. ...
- python psutil监控系统资源【转】
通过 运用 Python 第三方 系统 基础 模块, 可以 轻松 获取 服务 关键 运营 指标 数据,包括 Linux 基本 性能. 块 设备. 网卡 接口. 系统 信息. 网络 地址 库 等 信息. ...
- 探秘Java类加载
Java是一门面向对象的编程语言. 面向对象以抽象为基础,有封装.继承.多态三大特性. 宇宙万物,经过抽象,均可归入相应的种类.不同种类之间,有着相对井然的分别. Java中的类,便是基于现实世界中的 ...