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 ...
随机推荐
- 关于小程序 input 组件内容显示不全(显示的长度不满 input 宽度)问题
问题:小程序的input组件经常用到,但在使用input组件的时候会出现一种现象:明明设置了input的宽度,但是输入的内容显示的长度范围却怎么都不到一整个input组件的宽度,而且后面没显示的地方无 ...
- react安装极其了解
全局安装react脚手架工具 首先全局进行安装:cnpm install create-react-app -g 查看是否安装完成:create-react-app 创建react项目:create- ...
- Finders Keepers-freecodecamp算法题目
Finders Keepers 1.要求 写一个 function,它遍历数组 arr,并返回数组中第一个满足 func 返回值的元素. 举个例子,如果 arr 为 [1, 2, 3],func 为 ...
- 高并发架构系列:如何从0到1设计一个类Dubbo的RPC框架
在过去持续分享的几十期阿里Java面试题中,几乎每次都会问到Dubbo相关问题,比如:“如何从0到1设计一个Dubbo的RPC框架”,这个问题主要考察以下几个方面: 你对RPC框架的底层原理掌握程度. ...
- B1061 判断题 (15分)
B1061 判断题 (15分) 判断题的评判很简单,本题就要求你写个简单的程序帮助老师判题并统计学生们判断题的得分. 输入格式: 输入在第一行给出两个不超过 100 的正整数 N 和 M,分别是学生人 ...
- PTA 数据结构——是否完全二叉搜索树
7-2 是否完全二叉搜索树 (30 分) 将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果. 输入格 ...
- 二分答案:Poweroj2461-入门基础之二分答案(二分法的应用)
传送门:点击打开链接 入门基础之二分答案 Time Limit: 1000 MS Memory Limit: 65536 KBTotal Submit: 179 Accepted: 33 Page V ...
- Linux命令之----tree
命令简介 tree命令的中文意思为“树”,功能是以树形结构列出指定目录下的所有内容,包括所有文件.子目录及子目录里的目录和文件. 命令格式 tree [option] [directory]tree ...
- flex布局之flex-grow和flex-shrink如何计算
此文已由作者张含会授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 关于盒模型布局 如何实现两栏布局? (表格) 流式, 浮动, 定位 如何选择? 流式 > 浮动 > ...
- Python-S9——Day115-Flask Web框架
01 当日内容概要 1 当日内容概要 1.1 Flask基础: 1.2 Web框架包含的基础组件: 1.2.1 路由.视图函数.模板渲染: 1.3 Flask配置文件: 1.4 Flask的路由系统: ...