题目大意

给定一个长度\(\le100000\)的字符串

求每一个位置的最短识别子串

对于位置\(x\),能识别子串\(s[i...j]\)的条件是

1.\(i\le x \le j\)

2.\(s[i...j]\)在原串中只出现了一次

分析

从第二个条件入手

仅出现一次子串就是后缀树上\(|right|=1\)的子串

考虑贡献

该后缀左端点在\(left\)

长度范围\([L,R]\)

如图

对于\(A\)部分贡献的最短串长度为\(L\)

对于\(B\)部分贡献是等差数列\(i-lef+1\),提出\(1-lef\)

对上面分两棵线段树维护即可

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
const int M=200007;
const int INF=1e9+7; struct edge{int y,nxt;};
struct vec{
int g[M],te;
edge e[M];
vec(){memset(g,0,sizeof(g));te=0;}
void clear(){memset(g,0,sizeof(g));te=0;}
inline void push(int x,int y){e[++te].y=y;e[te].nxt=g[x];g[x]=te;}
inline int& operator () (int x){return g[x];}
inline edge& operator [] (int x){return e[x];}
}go; char s[M];
int n;
int ch[M][26];
int stp[M],fa[M];
int lef[M];
int last,tot;
int ans[M]; struct Seg{
int tag;
Seg(){tag=INF;}
}seg1[262147],seg2[262147]; int newnode(int ss){
stp[++tot]=ss;
return tot;
} int ext(int p,int q,int d){
int nq=newnode(stp[p]+1);
fa[nq]=fa[q]; fa[q]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;p&&ch[p][d]==q;p=fa[p]) ch[p][d]=nq;
return nq;
} int sam(int p,int d){
int np=ch[p][d];
if(np) return (stp[p]+1==stp[np]) ? np : ext(p,np,d); np=newnode(stp[p]+1);
for(;p&&!ch[p][d];p=fa[p]) ch[p][d]=np;
if(!p) fa[np]=1;
else{
int q=ch[p][d];
fa[np]= (stp[p]+1==stp[q]) ? q : ext(p,q,d);
}
return np;
} void mdf(Seg *S,int x,int l,int r,int tl,int tr,int d){
if(S[x].tag<=d) return;
if(tl<=l&&r<=tr) {S[x].tag=d;return;}
int mid=l+r>>1;
if(tl<=mid) mdf(S,x<<1,l,mid,tl,tr,d);
if(mid<tr) mdf(S,x<<1|1,mid+1,r,tl,tr,d);
} void get(Seg *S,int x,int l,int r,int nw,int kd){
nw=min(nw,S[x].tag);
if(l==r){
if(kd==0) ans[l]=min(ans[l],nw);
else ans[l]=min(ans[l],l+nw);
return;
}
int mid=l+r>>1;
get(S,x<<1,l,mid,nw,kd);
get(S,x<<1|1,mid+1,r,nw,kd);
} void dfs(int x){
int p,y;
for(p=go(x);p;p=go[p].nxt){
y=go[p].y;
dfs(y);
if(lef[y]){
if(lef[x]==0) lef[x]=lef[y];
else if(lef[x]>0) lef[x]=-1;
}
}
if(lef[x]>0){//if only one lef
int L=stp[fa[x]]+1;
int R=stp[x];
mdf(seg1,1,1,n,lef[x],lef[x]+L-1, L);
if(L!=R) mdf(seg2,1,1,n,lef[x]+L,lef[x]+R-1, 1-lef[x]);
}
} int main(){ int i;
scanf("%s",s+1);
n=strlen(s+1); last=tot=1;
for(i=n;i>0;i--){
last=sam(last,s[i]-'a');
lef[last]=i;
} for(i=2;i<=tot;i++) go.push(fa[i],i);
dfs(1); for(i=1;i<=n;i++) ans[i]=INF;
get(seg1,1,1,n,INF,0);
get(seg2,1,1,n,INF,1);
for(i=1;i<=n;i++) printf("%d\n",ans[i]); return 0;
}

bzoj 1396 识别子串 后缀树+线段树的更多相关文章

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

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

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

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

  3. bzoj 1396: 识别子串【SAM+线段树】

    建个SAM,符合要求的串显然是|right|==1的节点多代表的串,设si[i]为right集合大小,p[i]为right最大的r点,这些都可以建出SAM后再parent树上求得 然后对弈si[i]= ...

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

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

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

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

  6. BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)

    题目链接 SAM:能成为识别子串的只有那些|right|=1的节点代表的串. 设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-le ...

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

    手动博客搬家: 本文发表于20181221 00:58:26, 原地址https://blog.csdn.net/suncongbo/article/details/85150962 嗯,以后博客内容 ...

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

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

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

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

随机推荐

  1. V8引擎——详解

    前言 JavaScript绝对是最火的编程语言之一,一直具有很大的用户群,随着在服务端的使用(NodeJs),更是爆发了极强的生命力.编程语言分为编译型语言和解释型语言两类,编译型语言在执行之前要先进 ...

  2. python2, 3环境变量配置(win10下)

    1.找到此电脑,右击点击属性 2.左边侧栏,高级系统设置 3.系统属性中点击高级 4.点击环境变量 5.可以看到 某某某用户变量和系统变量两个方框 其中,系统变量是要你在打开cmd是用管理员身份运行所 ...

  3. HTTP 配置与编译安装

    目录 HTTP 配置与编译安装 HTTP 相关配置 DSO 定义'Main' Server 的文档页面路径 定义站点主页面 站点访问控制常见机制 基于源地址实现访问控制 日志设定 设定默认字符集 定义 ...

  4. Python学习——numpy.random

    numpy.random.rand numpy.random模块作用是生成随机数,其中numpy.random.rand(d0, d1, ..., dn):生成一个[0,1)之间的随机浮点数或N维浮点 ...

  5. linux正则表达式扩展部分

    扩展的正则表达式(Extended  Regular  Expressions): 使用的命令为:grep  -E以及egrep [了解即可] 1)+ 表示重复“一个或一个以上”前面的字符(*是0或多 ...

  6. (转)为什么在 2013 十月番中出现了很多以 3D 渲染代替传统 2D 绘画来表现人物的镜头?

    一直都有的,特别是三次元这家公司一直致力于3d的风格化渲染既大家说的3d转2d.目前最厉害的商业化软件是pencil+,占领大部分的作品.而mentalray,早期用于disney的部分风格化渲染:i ...

  7. JZOJ 5775. 【NOIP2008模拟】农夫约的假期

    5775. [NOIP2008模拟]农夫约的假期 (File IO): input:shuru.in output:shuru.out Time Limits: 1000 ms  Memory Lim ...

  8. OpenCV学习笔记(九) 重映射、仿射变换

    重映射 通过重映射来表达每个像素的位置  : 这里  是目标图像,  是源图像,  是作用于  的映射方法函数.想象一下我们有一个图像  , 我们想满足下面的条件作重映射:,图像会按照  轴方向发生翻 ...

  9. Python高级主题:Python ABC(抽象基类)

    #抽象类实例 作用统一规范接口,降低使用复杂度.import abcclass Animal(metaclass = abc.ABCMeta): ##只能被继承,不能实例化,实例化会报错 @abc.a ...

  10. 4 Template层-验证码

    1.验证码 在用户注册.登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻一些服务器的压力 使用验证码也是一种有效的防止crsf的方法 验证码效果如下图: 官网 ...