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

Input
Output
Sample Input
Sample Output
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4
解题思路:
思考一个最小识别串会带来什么。
在它内部的点的答案就是这个串的长度,而在它外面的点需要拓展到这个串的端点。
首先,一个Parent树内的节点对应子串是唯一识别的,那么其|Right|必定=1,那么对应一个|Right|=1的节点
因为Parent树上的节点是其子节点的后缀,而Parent树是逆序的,所以一棵|Right|=1的子树内结尾是一定的,设为endpos。
那么在一个|Right|=1的节点内其有效压缩长度为len-len[fa],那么这段子串可以认为是等价唯一的。其长度为其到endpos的距离。
而在len[fa]以下的,识别长度太小必须使用len[fa]为最小识别长度。
区间修改当然要线段树了。
在len[fa]~len区间内,其答案为endpos-pos+1。
在1~len[fa]区间内,其答案为len[fa]
pos是与位置有关的变量最后算。
只需将endpos-1,len[fa]推入线段树好了
代码:
(不要问我为什么上次拓扑这次建边因为我闲的)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lll spc<<1
#define rrr spc<<1|1
struct sant{
int tranc[];
int len;
int pre;
}s[];
struct pnt{
int hd;
int wgt;
int endp;
}p[];
struct ent{
int twd;
int lst;
}e[];
struct trnt{
int minval;
int lzt;
bool al;
};
int cnt;
int siz;
int fin;
int n;
char tmp[];
class Sgmt_tree{
public:
void res(void)
{
for(int i=;i<;i++)
tr[i].lzt=tr[i].minval=0x3f3f3f3f;
return ;
}
void pushup(int spc)
{
tr[spc].minval=std::min(tr[lll].minval,tr[rrr].minval);
return ;
}
void Add(int spc,int x)
{
tr[spc].minval=std::min(tr[spc].minval,x);
tr[spc].lzt=std::min(tr[spc].lzt,x);
tr[spc].al=true;
return ;
}
void pushdown(int spc)
{
if(tr[spc].al)
{
Add(lll,tr[spc].lzt);
Add(rrr,tr[spc].lzt);
tr[spc].al=false;
}
return ;
}
void update(int l,int r,int ll,int rr,int spc,int v)
{
if(l>rr||ll>r)
return ;
if(ll<=l&&r<=rr)
{
Add(spc,v);
return ;
}
int mid=(l+r)>>;
pushdown(spc);
update(l,mid,ll,rr,lll,v);
update(mid+,r,ll,rr,rrr,v);
pushup(spc);
return ;
}
int query(int l,int r,int pos,int spc)
{
if(l==r)
return tr[spc].minval;
int mid=(l+r)>>;
pushdown(spc);
if(pos<=mid)
return query(l,mid,pos,lll);
else
return query(mid+,r,pos,rrr);
}
private:
trnt tr[];
}T[];
void Insert(int c,int w)
{
int nwp,nwq,lsq,lsp;
nwp=++siz;
p[nwp].wgt=;
p[nwp].endp=w;
s[nwp].len=s[fin].len+;
for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)
s[lsp].tranc[c]=nwp;
if(!s[lsp].tranc[c])
s[lsp].tranc[c]=nwp;
else{
lsq=s[lsp].tranc[c];
if(s[lsq].len==s[lsp].len+)
s[nwp].pre=lsq;
else{
nwq=++siz;
s[nwq]=s[lsq];
s[nwq].len=s[lsp].len+;
s[nwp].pre=s[lsq].pre=nwq;
while(s[lsp].tranc[c]==lsq)
{
s[lsp].tranc[c]=nwq;
lsp=s[lsp].pre;
}
}
}
fin=nwp;
return ;
}
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
return ;
}
void Dfs(int x)
{
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
Dfs(to);
p[x].wgt+=p[to].wgt;
p[x].endp=std::min(p[x].endp,p[to].endp);
}
if(p[x].wgt==)
{
int minlen=s[s[x].pre].len+;
int maxlen=s[x].len;
int endpos=p[x].endp;
T[].update(,n,endpos-maxlen+,endpos-minlen+,,endpos+);
T[].update(,n,endpos-minlen+,endpos,,minlen);
}
return ;
}
int main()
{
scanf("%s",tmp+);
n=strlen(tmp+);
for(int i=;i<=n;i++)
Insert(tmp[i]-'a',i);
for(int i=;i<=siz;i++)
ade(s[i].pre,i);
T[].res();
T[].res();
Dfs();
for(int i=;i<=n;i++)
{
int ans1,ans2;
ans1=T[].query(,n,i,)-i;
ans2=T[].query(,n,i,);
printf("%d\n",std::min(ans1,ans2));
}
return ;
}
BZOJ1396: 识别子串(后缀自动机,线段树)的更多相关文章
- BZOJ1396: 识别子串(后缀自动机 线段树)
题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...
- 【BZOJ1396】识别子串 - 后缀自动机+线段树
题意: Description Input 一行,一个由小写字母组成的字符串S,长度不超过10^5 Output L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. 题解: ...
- bzoj1396&&2865 识别子串 后缀自动机+线段树
Input 一行,一个由小写字母组成的字符串S,长度不超过10^5 Output L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. Sample Input agoodco ...
- BZOJ 1396&&2865 识别子串[后缀自动机 线段树]
Description 在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件: 1.i≤K≤j. 2.子串T只在S中出现过一次. 例如, ...
- BZOJ 1396 识别子串 (后缀自动机+线段树)
题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...
- bzoj 1396/2865: 识别子串 后缀自动机+线段树
水水的字符串题 ~ #include <map> #include <cstdio> #include <cstring> #include <algorit ...
- BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...
- BZOJ1396 识别子串 字符串 SAM 线段树
原文链接http://www.cnblogs.com/zhouzhendong/p/9004467.html 题目传送门 - BZOJ1396 题意 给定一个字符串$s$,$|s|\leq 10^5$ ...
- 2018.12.23 bzoj2865&&1396: 字符串识别(后缀自动机+线段树)
传送门 卡空间差评! 题意简述:给一个字串,对于每个位置求出经过这个位置且只在字串中出现一次的子串的长度的最小值. 解法:先建出samsamsam,显然只有当sizep=1size_p=1sizep ...
- bzoj1396识别子串(SAM+线段树)
复习SAM板子啦!考前刷水有益身心健康当然这不是板子题/水题…… 很容易发现只在i位置出现的串一定是个前缀串.那么对答案的贡献分成两部分:一部分是len[x]-fa~len[x]的这部分贡献会是r-l ...
随机推荐
- ios 文件上传, post数据
转自:http://www.maxiaoguo.com/clothes/267.html 一.文件下载 获取资源文件大小有两张方式 1. HTTP HEAD方法 NSMutableURLRequest ...
- Android设计模式(十二)--抽象工厂模式
问题: 抽象工厂模式,是一个,狠恶心的模式,那么这个模式在Android有没实用到过呢? 1.定义: 抽象工厂模式:为创建一组相关或者是相互依赖的对象提供一个接口,而不须要指定他们的详细类. 2.使用 ...
- BZOJ5106: [CodePlus2017]汀博尔
[传送门:BZOJ5106] 简要题意: 给出n棵树,初始高度为h[i],每棵树每个月长高a[i] 现有一个客户,需要至少s长的总木材,而且每次截取的木材必须是一整颗树而且高度大于等于L 求出最少的月 ...
- HTTP 各种特性应用(二)
一.Cookie 通过 Set-Cookie 设置. 下次浏览器请求就会带上. 键值对,可以设置多个. Cookie 属性 max-age 和 expires 设置过期时间 Secure 只在 htt ...
- 使用 HTML5 canvas制作拾色器
自制的拾色器漂亮吧,哈哈 废话不多说直接上代码,希望可以帮到需要的朋友 <html><head> <style> .canvas_color{p ...
- matlab中tic和toc使用方法
tic和toc用来记录matlab命令运行的时间. tic用来保存当前时间,而后使用toc来记录程序完毕时间. 两者往往结合使用,使用方法例如以下: 程序代码: tic operations t ...
- vue -- config.js 配置跨域文件
1.在使用vue开发的时候经常要涉及到跨域的问题,其实在vue cli中是有我们设置跨域请求的文件的. 2.当跨域无法请求的时候我们可以修改工程下config文件夹下的index.js中的dev -- ...
- 关于exports 和 module.exports
本文来源为node.js社区附上链接 http://cnodejs.org/topic/5231a630101e574521e45ef8 require 用来加载代码,而 exports 和 modu ...
- Spark Tachyon编译部署(含单机和集群模式安装)
Tachyon编译部署 编译Tachyon 单机部署Tachyon 集群模式部署Tachyon 1.Tachyon编译部署 Tachyon目前的最新发布版为0.7.1,其官方网址为http://tac ...
- IDC机房KVM应用案例分析
IDC机房KVM应用案例分析 一.背景介绍 随着信息技术的发展,各行各业都在马不停蹄的开展着各自的信息化建设步伐.对于设计制造创新科技产品为运行主业的设计院而言,内部IT基础设备与机房管理结构的完善与 ...