Description

Input

一行,一个由小写字母组成的字符串S,长度不超过10^5

Output

L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

Sample Input

agoodcookcooksgoodfood

Sample Output

1
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: 识别子串(后缀自动机,线段树)的更多相关文章

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

    题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...

  2. 【BZOJ1396】识别子串 - 后缀自动机+线段树

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

  3. bzoj1396&&2865 识别子串 后缀自动机+线段树

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

  4. BZOJ 1396&&2865 识别子串[后缀自动机 线段树]

    Description 在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件: 1.i≤K≤j. 2.子串T只在S中出现过一次. 例如, ...

  5. BZOJ 1396 识别子串 (后缀自动机+线段树)

    题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...

  6. bzoj 1396/2865: 识别子串 后缀自动机+线段树

    水水的字符串题 ~ #include <map> #include <cstdio> #include <cstring> #include <algorit ...

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

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

  8. BZOJ1396 识别子串 字符串 SAM 线段树

    原文链接http://www.cnblogs.com/zhouzhendong/p/9004467.html 题目传送门 - BZOJ1396 题意 给定一个字符串$s$,$|s|\leq 10^5$ ...

  9. 2018.12.23 bzoj2865&&1396: 字符串识别(后缀自动机+线段树)

    传送门 卡空间差评! 题意简述:给一个字串,对于每个位置求出经过这个位置且只在字串中出现一次的子串的长度的最小值. 解法:先建出samsamsam,显然只有当sizep=1size_p=1sizep​ ...

  10. bzoj1396识别子串(SAM+线段树)

    复习SAM板子啦!考前刷水有益身心健康当然这不是板子题/水题…… 很容易发现只在i位置出现的串一定是个前缀串.那么对答案的贡献分成两部分:一部分是len[x]-fa~len[x]的这部分贡献会是r-l ...

随机推荐

  1. OpenCV图像处理篇之边缘检測算子

    3种边缘检測算子 灰度或结构等信息的突变位置是图像的边缘,图像的边缘有幅度和方向属性.沿边缘方向像素变化缓慢,垂直边缘方向像素变化剧烈.因此,边缘上的变化能通过梯度计算出来. 一阶导数的梯度算子 对于 ...

  2. 离散化求RECT1

    本文转载至点击打开链接 #include<stdio.h> struct node{ int x1,y1,x2,y2,c; }; struct node s[1010]; int px[2 ...

  3. Docker Network Configuration 高级网络配置

    Network Configuration TL;DR When Docker starts, it creates a virtual interface named docker0 on the ...

  4. XML结构,写到TreeView树上

    http://blog.csdn.net/ztzi321/article/details/44077563

  5. 电脑无法上网,DHCP客户端不能正确获取IP地址

    问题特征:DHCP服务器更新[保留]配置信息后,给一客户端绑定了新的IP地址;但客户端IP地址并未正确更新; 处理: 一.检查DHCP服务器配置; 1.MAC地址.IP地址均正确;并已“添加到筛选器” ...

  6. 再次学习 Iterator 迭代器 与 Generator 生成器

    Iterator : 返回的结果是:{value, done} function chef(foods){ let i = 0; return { next(){ let done = ( i> ...

  7. 10G安装DataGuard

    最后更新时间:2013年8月4日,星期日 ★ oracle 10G安装环境 数据库软件安装环境不详细描述,网上到处有这方面资料,下面只简单描述下. 也可参考官方文档: http://docs.orac ...

  8. 六台机器搭建RedisCluster分布式集群

    原文:六台机器搭建RedisCluster分布式集群 版权声明:m_nanle_xiaobudiu https://blog.csdn.net/m_nanle_xiaobudiu/article/de ...

  9. PyCharm激活方法

    1.激活码激活 1.修改hosts文件 将0.0.0.0 account.jetbrains.com添加到hosts文件最后,windows系统hosts文件路径为:C:\windows\system ...

  10. Java 学习(13):抽象类& 抽象方法& 封装

    目录 --- 抽象类 --- 封装 抽象类: 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的 ...