BZOJ1396 识别子串 字符串 SAM 线段树
原文链接http://www.cnblogs.com/zhouzhendong/p/9004467.html
题目传送门 - BZOJ1396
题意
给定一个字符串$s$,$|s|\leq 10^5$。
对于$s$的每一个位置,求$s$的包含该位置的、仅在$s$中出现一次的连续子串的最短长度。
题解
考虑先对于$s$构建一个后缀自动机。
由于我们要考虑的串是只能在$s$中出现一次的。
所以我们先基数排序,然后通过$fa$指针计算每一个节点的$Right$集合。
只出现一次的就是$Right$集合大小为$1$的。
对于$Right$大小为$1$的节点$i$,首先我们得知$s[Right(i)-Max(i)+1\cdots Right(i)]$是只出现一次的,所以我们开个线段树,直接标记永久化,让$Right(i)-Max(i)+1\cdots Right(i)$的答案对于$Max(i)$取个$\min$。又考虑到$s[Right(i)-j+1\cdots Right(i)|Max(i)\geq j > Max(fa(i))]$也是只出现一次的,只不过区间对某一个定值取$\min$改成了对等差数列取$\min$而已。
于是只需要开两棵标记永久化的线段树即可。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int n,Min[N<<2],Min2[N<<2];
int root=1,size=1,last=1;
int plast[N],tax[N],totend[N<<1],id[N<<1];
char s[N];
struct SAM{
int Next[26],fa,Max;
}t[N<<1];
void extend(int c){
int p=last,np=++size,q,nq;
t[np].Max=t[p].Max+1;
for (;!t[p].Next[c];p=t[p].fa)
t[p].Next[c]=np;
q=t[p].Next[c];
if (t[q].Max==t[p].Max+1)
t[np].fa=q;
else {
nq=++size;
t[nq]=t[q],t[nq].Max=t[p].Max+1;
t[q].fa=t[np].fa=nq;
for (;t[p].Next[c]==q;p=t[p].fa)
t[p].Next[c]=nq;
}
last=np;
}
void build(int rt,int L,int R){
Min[rt]=n,Min2[rt]=n*2;
if (L==R)
return;
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
build(ls,L,mid);
build(rs,mid+1,R);
}
void update1(int rt,int L,int R,int xL,int xR,int v){
if (L>xR||xL>R)
return;
if (xL<=L&&R<=xR){
Min[rt]=min(Min[rt],v);
return;
}
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
update1(ls,L,mid,xL,xR,v);
update1(rs,mid+1,R,xL,xR,v);
}
void update2(int rt,int L,int R,int xL,int xR,int v){
if (L>xR||xL>R)
return;
if (xL<=L&&R<=xR){
Min2[rt]=min(Min2[rt],v);
return;
}
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
update2(ls,L,mid,xL,xR,v);
update2(rs,mid+1,R,xL,xR,v-(mid-L+1));
}
int query(int rt,int L,int R,int x){
if (L==R)
return min(Min[rt],Min2[rt]);
int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
if (x<=mid)
return min(query(ls,L,mid,x),min(Min[rt],Min2[rt]-(x-L)));
else
return min(query(rs,mid+1,R,x),min(Min[rt],Min2[rt]-(x-L)));
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
t[0].Max=-1;
for (int i=0;i<26;i++)
t[0].Next[i]=1;
for (int i=1;i<=n;i++)
extend(s[i]-'a'),plast[i]=last;
for (int i=1;i<=size;i++)
tax[t[i].Max]++;
for (int i=1;i<=n;i++)
tax[i]+=tax[i-1];
for (int i=1;i<=size;i++)
id[tax[t[i].Max]--]=i,totend[i]=-1;
for (int i=1;i<=n;i++)
totend[plast[i]]=i;
for (int i=size;i>=1;i--){
int &fa=totend[t[id[i]].fa],&now=totend[id[i]];
fa=fa==-1?now:-2;
}
build(1,1,n);
for (int i=2;i<=size;i++){
if (totend[i]<0)
continue;
int p3=totend[i],p2=p3-t[i].Max+1,p1=p3-t[t[i].fa].Max;
update1(1,1,n,p1,p3,t[t[i].fa].Max+1);
update2(1,1,n,p2,p1,t[i].Max+(p2-1));
}
for (int i=1;i<=n;i++)
printf("%d\n",query(1,1,n,i));
return 0;
}
BZOJ1396 识别子串 字符串 SAM 线段树的更多相关文章
- bzoj1396识别子串(SAM+线段树)
复习SAM板子啦!考前刷水有益身心健康当然这不是板子题/水题…… 很容易发现只在i位置出现的串一定是个前缀串.那么对答案的贡献分成两部分:一部分是len[x]-fa~len[x]的这部分贡献会是r-l ...
- bzoj 1396: 识别子串【SAM+线段树】
建个SAM,符合要求的串显然是|right|==1的节点多代表的串,设si[i]为right集合大小,p[i]为right最大的r点,这些都可以建出SAM后再parent树上求得 然后对弈si[i]= ...
- BZOJ1396: 识别子串(后缀自动机 线段树)
题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...
- BZOJ1396 识别子串【SAM+SegmentTree】
BZOJ1396 识别子串 给定一个串\(s\),对于串中的每个位置,输出经过这个位置且只在\(s\)中出现一次的子串的最短长度 朴素的想法是,我们要找到那些只出现一次的子串,之后遍历每个串,把串所覆 ...
- 【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: 识别子串( 后缀数组 + 线段树 )
这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...
- UOJ#395. 【NOI2018】你的名字 字符串,SAM,线段树合并
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ395.html 题解 记得同步赛的时候这题我爆0了,最暴力的暴力都没调出来. 首先我们看看 68 分怎么做 ...
随机推荐
- 30)django-ORM(元信息,级联删除,正反向操作,连表查询优化)
一:元信息 class User(models.Model): name=models.CharField(max_length,index=True) email=model.CharField(m ...
- python 列表,字典,元组,字符串,常用函数
飞机票 一.列表方法 1.ls.extend(object) 向列表ls中插入object中的每个元素,object可以是字符串,元组和列表(字符串“abc”中包含3个元组),相当于ls和object ...
- Oracle 数据库导入与出
Oracle 数据库导入与出 导出( EXPORT )是用 EXP 将数据库部分或全对象的结构和导出 . 导入( 导入( IMPORT )是用 )是用 IMP IMP将 OS 文件中的对象结构和数据装 ...
- Confluence 6 通过 SSL 或 HTTPS 运行 - 确定你的证书路径
在默认的情况下,Tomcat 希望 keystore 文件被命名为 .keystore 文件,同时这个文件应该放置在 Tomcat 运行的 home 目录中(这个目录可能与你自己的 Home 目录的路 ...
- Confluence 6 禁用管理员联系表单
如果你希望禁用这个功能,不允许用户通过发送电子邮件的方式联系站点管理员.你可以禁用这个页面中有关输入用户信息发送电子邮件的部分.你只能禁用用户电子邮件输入表单,如果你按照上面描述的步骤在 'Custo ...
- Confluence 6 中样式化字体
Confluence 提供了通过层叠样式表(CSS)调整页面展示情况的能力.本页面帮助你理解如何在 Confluence 中使用一些 CSS 样式修改字体样式和字体大小. 下面的代码为自定义的字体代码 ...
- 高性能JavaScript读后感
这本书让lz对js性能优化有了更深刻的理解,现在因为我们通常用第三方构建工具webpack.gulp等诸如此类,之前总是听说什么dom操作影响性能呢,对这个概念总是有点模糊,但看完这本书之后后,相对而 ...
- 断路器Ribbon
断路器:就是对服务访问不到的情况做出自己的错误,也就是故障转移(将当前出现故障的请求重新返回特定消息) 改造消费者项目(RibbonDemo) 1.在pom.xml中引入hystrix的jar包 &l ...
- css样式之属性操作
一.文本属性 1.text-align:cnter 文本居中 2.line heigth 垂直居中 :行高,和高度对应 3.设置图片与文本的距离:vertical-align 4.text-decor ...
- VGG-Net
论文下载 源码GitHub 目的 这篇文章是以比赛为目的——解决ImageNet中的1000类图像分类和定位问题.在此过程中,作者做了六组实验,对应6个不同的网络模型,这六个网络深度逐渐递增的同时,也 ...