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 ...
随机推荐
- swift学习之数组
首先数组的定义:以有序的方式存储同样类型的值 (1)数组的简写(shorthand)语法 你能够通过Array<Element>,在这里,Element时数组存储元素的值的类型.也能够通过 ...
- 《TCP/IP具体解释》读书笔记(19章)-TCP的交互数据流
在TCP进行传输数据时.能够分为成块数据流和交互数据流两种.假设按字节计算.成块数据与交互数据的比例约为90%和10%,TCP须要同一时候处理这两类数据,且处理的算法不同. 书籍本章中以Rlogin应 ...
- Java 8 时间日期库的20个使用演示样例
除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务演示样例来学习怎样使用Java 8的这套API.Java对日 ...
- beego orm commonDAL通用方法汇总
orm 通用方法——QueryModelById 主键查询 orm 通用方法——GetOneModel 条件查询一个对象 orm 通用方法——QueryModelCount条件查询记录数 orm 通用 ...
- linux RAC 安装失败完全卸载
1,删除软件安装目录 rm -rf /u01/app 2,删除以下目录内容 rm -rf /tmp/.oracle rm -rf /tmp/* rm -rf /tmp/ora* rm -rf ...
- 深入理解Core Data
留给我这忘事精看 Core Data 是什么? 大概八年前,2005年的四月份,Apple 公布了 OS X 10.4,正是在这个版本号中 Core Data 框架公布了.那个时候 YouTube 也 ...
- 自己定义控件-DownSlidingDrawer
一.描写叙述 能够下拉的 SlidingDrawer 二.效果图 图片是网上找到,可是效果是一样的 三.源代码 https://github.com/mentor811/Demo_MySlidingD ...
- python-打开网页
最近一直想通过python来实现网页的操作.因为想把自己vimrc的配置直接通过脚本来实现.比较理想的情况下,就是通过一个脚本,把自己需要的一些资源直接从网上下载下来,然后再对下载的资源进行安装等操作 ...
- jquery插件库http://www.jq22.com/
http://www.jq22.com/ http://www.jq22.com/jquery/%E5%8A%A0%E8%BD%BD http://www.jq22.com/jquery/%E5%BC ...
- How to install Armbian on Orange Pi Plus 2e
bian on Orange Pi Plus 2e How to install Armbian on Orange Pi Plus 2e Armbian on the microSD You jus ...