bzoj 1396 识别子串 后缀树+线段树
题目大意
给定一个长度\(\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 识别子串 后缀树+线段树的更多相关文章
- BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...
- BZOJ 1396 识别子串 (后缀自动机+线段树)
题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...
- bzoj 1396: 识别子串【SAM+线段树】
建个SAM,符合要求的串显然是|right|==1的节点多代表的串,设si[i]为right集合大小,p[i]为right最大的r点,这些都可以建出SAM后再parent树上求得 然后对弈si[i]= ...
- BZOJ1396: 识别子串(后缀自动机 线段树)
题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...
- BZOJ 1396&&2865 识别子串[后缀自动机 线段树]
Description 在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件: 1.i≤K≤j. 2.子串T只在S中出现过一次. 例如, ...
- BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)
题目链接 SAM:能成为识别子串的只有那些|right|=1的节点代表的串. 设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-le ...
- BZOJ 1396 识别子串 (后缀自动机、线段树)
手动博客搬家: 本文发表于20181221 00:58:26, 原地址https://blog.csdn.net/suncongbo/article/details/85150962 嗯,以后博客内容 ...
- 【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 ...
随机推荐
- 认识mysql(1)
---恢复内容开始--- 1.MySQL概述 1.什么是数据库? 存储数据的仓库 2.都有哪些公司在用数据库? 金融机构.游戏公司.购物网站.论坛网站... 3.提供数据库服务的软件? 1.软件分类 ...
- git 命令汇总
本地库处理 git init 初始化仓库 git clone [地址] 下载项目 git status 查看当前暂存等状态 git add 添加暂存 cat .git/config 查看git配置 l ...
- js数组中去重对象
var allCourses = new Array();var coursesId = new Array();function findCourses() { Courses.data().eac ...
- 对数据仓库Hive的一些认识
首先我们得明白什么是数据仓库? 数据仓库,英文名称为Data warehouse,可简写为DW或DWH.数据仓库的目的是构建面向分析的集成化数据环境,为企业提供决策支持(Decision Supp ...
- 团体程序设计天梯赛-练习集 L2-001 紧急救援 (25 分)
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图.在地图上显示有多个分散的城市和一些连接城市的快速道路.每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上.当其他城市有紧急求 ...
- jichu
第 题 请编写函数 fun,其功能时:计算并输出当 x<0.97 时下列多项式的值,直到| sn-s(n-)|<0.000001 为止. Sn=+.5x+)/!x()+…+)()…..() ...
- spark 的createDstream和createDirectStream区别
spark读取kafka数据流提供了两种方式createDstream和createDirectStream. 两者区别如下: 1.KafkaUtils.createDstream 构造函数为Kafk ...
- codeforce GYM 100741 A Queries
A. Queries time limit per test:0.25 s memory limit per test:64 MB input:standard input output:standa ...
- java流、文件以及IO
读写文件 一个流被定义为一个数据序列.输入流用于从源读取数据,输出流用于向目标写数据. 输入流和输出流的类层次图. FileInputStream FileInputStream用于从文件中读取数据, ...
- Python抓取视频内容
Python抓取视频内容 Python 是一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年.Python语法简洁而清晰,具 ...