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 ...
随机推荐
- nodeJs学习路线
转载自:http://blog.fens.me/nodejs-roadmap/ 前言 用Nodejs已经1年有余,陆陆续续写了48篇关于Nodejs的博客文章,用过的包有上百个. 和全部人一样,我也从 ...
- vue29-vue2.0组件通信_recv
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- win7防火墙里开启端口的图文教程
转载于:http://www.cnblogs.com/vipsoft/archive/2012/05/02/2478847.html 开启端口:打开“控制面板”中的“Windows防火墙”,点击左侧的 ...
- JS — 对象的基本操作
JS面向对象系列教程 — 对象的基本操作 面向对象概述  面向对象(Object Oriented)简称OO,它是一种编程思维,用于指导我们如何应对各种复杂的开发场景. 这里说的对象(Object) ...
- tensorflow学习之路-----简单卷积神经网路
import tensorflow as tf#取数据,目的是辨别数字from tensorflow.examples.tutorials.mnist import input_data'''手动添加 ...
- flex RemoteObject 的两种使用方法
这里使用的是django1.6 和 postgreSQL9.0 FlashBuilder4.5 django方面就不说了,根据文档来做,建好模块,配置好数据库等等 创建 gateway 和 time ...
- CODEVS——T1961 躲避大龙
http://codevs.cn/problem/1961/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 De ...
- eXtremeDB相关问题解答(3)
> 1. Could our database support multi-database under one single instance? > > 2. ...
- Shiro结合Redis解决集群中session同步问题
pom.xml文件中引入redis的依赖 在application.xml配置redis: <bean id="jedisConnectionFactory" class=& ...
- 你必须要知道的几个CSS技巧
有些经典的CSS技巧,我们还是需要记住的,这样可以节省我们大量的时间,下面零度就为大家推荐几个比较好的CSS技巧: 1.在不同页面上使用同样的导航代码 许多网页上都有导航菜单,当进入某页时,菜单上相应 ...