字符串识别

2865: 字符串识别

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 839  Solved: 261
[Submit][Status][Discuss]

Description

XX在进行字符串研究的时候,遇到了一个十分棘手的问题。

在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件:

1、i≤K≤j。

2、子串T只在S中出现过一次。

例如,S="banana",K=5,则关于第K位的识别子串有"nana","anan","anana","nan","banan"和"banana"。

现在,给定S,XX希望知道对于S的每一位,最短的识别子串长度是多少,请你来帮助他。

Input

仅一行,输入长度为N的字符串S。

Output

输出N行,每行一个整数,第i行的整数表示对于第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

HINT

N<=5*10^5

Source

[Submit][Status][Discuss]

HOME
Back


jklover的题解

SAM + 线段树.

先建出 parent 树,按照题意,我们只需要处理 right 集合大小为 1 的节点.

如下图,先算出这样的一个节点合法长度的 max,min ( min 可以用 max(fa)+1 计算).

![](https://jkloverdcoi.github.io/2019/04/27/bzoj-1396-%E8%AF%86%E5%88%AB%E5%AD%90%E4%B8%B2/1.png)

那么区域 I 内每个点的贡献就是区域 II 的长度加上这个点到区域 II 的距离.
区域 II 内每个点的贡献就是区间 II 的长度.开两颗线段树分别修改就可以了.

如何维护区域1呢?考虑他的答案是pos[u]-i+1,直接更新pos[u],那么把最终线段树上的值-i就是答案了。这种操作比较常见。

时间复杂度\(O(n \log n)\)

co int N=2e5,INF=0x3f3f3f3f;
struct node{int min,tag;};
#define lc (x<<1)
#define rc (x<<1|1)
struct SegTree{
node t[N*4];
void pushup(int x){
t[x].min=min(t[lc].min,t[rc].min);
}
void modify(int x,int v){
t[x].min=min(t[x].min,v),t[x].tag=min(t[x].tag,v);
}
void pushdown(int x){
if(t[x].tag<INF){
modify(lc,t[x].tag),modify(rc,t[x].tag);
t[x].tag=INF;
}
}
void build(int x,int l,int r){
t[x].min=t[x].tag=INF;
if(l==r) return;
int mid=l+r>>1;
build(lc,l,mid),build(rc,mid+1,r);
}
void update(int x,int l,int r,int ql,int qr,int v){
if(ql<=l&&r<=qr) return modify(x,v);
pushdown(x);
int mid=l+r>>1;
if(ql<=mid) update(lc,l,mid,ql,qr,v);
if(qr>mid) update(rc,mid+1,r,ql,qr,v);
pushup(x);
}
}T1,T2;
int ans[N];
void query(int x,int l,int r){
if(l==r) return ans[l]=min(T1.t[x].min-l,T2.t[x].min),void();
T1.pushdown(x),T2.pushdown(x);
int mid=l+r>>1;
query(lc,l,mid),query(rc,mid+1,r);
}
// SAM
char buf[N];
int n,tot=1,last=1;
int ch[N][26],fa[N],len[N],pos[N],siz[N];
void extend(int c,int po){
int p=last,cur=last=++tot;
len[cur]=len[p]+1,pos[cur]=po,siz[cur]=1;
for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
if(!p) fa[cur]=1;
else{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[cur]=q;
else{
int clone=++tot;
memcpy(ch[clone],ch[q],sizeof ch[q]);
fa[clone]=fa[q],len[clone]=len[p]+1,pos[clone]=pos[q];
fa[q]=fa[cur]=clone;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
}
}
}
int cnt[N],ord[N];
int main(){
scanf("%s",buf+1),n=strlen(buf+1);
for(int i=1;i<=n;++i) extend(buf[i]-'a',i);
for(int i=1;i<=tot;++i) ++cnt[len[i]];
for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
for(int i=1;i<=tot;++i) ord[cnt[len[i]]--]=i;
T1.build(1,1,n),T2.build(1,1,n);
for(int i=tot;i>=1;--i){
int u=ord[i];
siz[fa[u]]+=siz[u];
if(u==1||siz[u]>1) continue;
int l=pos[u]-len[u]+1,r=pos[u]-len[fa[u]];
if(l<=r-1) T1.update(1,1,n,l,r-1,pos[u]+1);
T2.update(1,1,n,r,pos[u],len[fa[u]]+1);
}
query(1,1,n);
for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
return 0;
}

BZOJ1396 识别子串 和 BZOJ2865 字符串识别的更多相关文章

  1. bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】

    根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[ ...

  2. 【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)

    [BZOJ1396]识别子串&[BZOJ2865]字符串识别(后缀自动机) 题面 自从有了DBZOJ 终于有地方交权限题了 题解 很明显,只出现了一次的串 在\(SAM\)的\(right/e ...

  3. bzoj2865 字符串识别

    Description XX在进行字符串研究的时候,遇到了一个十分棘手的问题. 在这个问题中,给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件: ...

  4. bzoj千题计划319:bzoj2865: 字符串识别(后缀自动机 + 线段树)

    https://www.lydsy.com/JudgeOnline/problem.php?id=2865 同上一篇博客 就是卡卡空间,数组改成map #include<map> #inc ...

  5. 【bzoj1396】 识别子串

    http://www.lydsy.com/JudgeOnline/problem.php?id=1396 (题目链接) 题意 问字符串S每一位的最短识别子串是多长(识别子串指包含这个字符且只出现在S中 ...

  6. 【BZOJ-1396&2865】识别子串&字符串识别 后缀自动机/后缀树组 + 线段树

    1396: 识别子串 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 312  Solved: 193[Submit][Status][Discuss] ...

  7. [BZOJ1396&2865]识别子串

    bzoj1396 bzoj2865 dbzoj1396 dbzoj2865 题面 XX在进行字符串研究的时候,遇到了一个十分棘手的问题. 在这个问题中,给定一个字符串\(S\),与一个整数\(K\), ...

  8. BZOJ1396:识别子串(SAM)

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

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

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

随机推荐

  1. 倒数第K个结点

    typedef struct Lnode{ int data; struct Lnode *next; }Lnode,*Link; Link fi(Link head,int k){ Link fa ...

  2. ubuntu18.04LTS服务器用vituralenv安装和配置pytorch和tensorflow

    ============tensorflow================= $ python3 -m venv tf14====输入例子====# $ vim ~/.bashrc #(添加如下行, ...

  3. docker安装nginx , 安装mysql5.6,安装redis3.2

    安装nginx 拉取镜像 docker  pull nginx 查看镜像 docker  images 创建多个目录 mkdir -p  /data/nginx/{conf,conf.d,html,l ...

  4. strings包 — 汇总

    转自:https://www.jb51.net/article/148388.htm strings 包中的函数和方法 // Count 计算字符串 sep 在 s 中的非重叠个数 // 如果 sep ...

  5. 常用Tables控件介绍(三)

    向datagrid中添加临时记录: 代码: $(function(){ fun={ add:function(){ $.ajaxSettings.async=false; var rows=$('#d ...

  6. nRF24L01/nRF24L01+应用总结

    nRF24L01+是nRF24L01的升级款,比较显眼的区别是nRF24L01+比nRF24L01多了一个250Kbps传输速率.其它的还有接收模式官方给的耗电量是不一样的.个别寄存器名字不一样. 接 ...

  7. ORACLE链接SQLSERVER数据库数据操作函数范例

    ORACLE链接SQLSERVER数据库数据操作函数范例 create or replace function FUN_NAME(LS_DJBH IN varchar2 ,LS_ITM varchar ...

  8. 简单的3D森林

    package { import flash.display.Sprite; public class Tree extends Sprite { public var xpos:Number = 0 ...

  9. 面试4 --- constructor必须与class同名,但方法不能与class同名?

    选 C “constructor必须与class同名,但方法不能与class同名”这句话是错误的,方法是可以和class同名的:方法可以和类名同名的,和构造方法唯一的区别就是,构造方法没有返回值.

  10. Hadoop1-认识Hadoop大数据处理架构

    一.简介概述 1.什么是Hadoop Hadoop是Apache软件基金会旗下的一个开源分布式计算平台,为用户提供了系统底层细节透明的分布式基础架构 Hadoop是基于java语言开发,具有很好的跨平 ...