字符串识别

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. C# 编译器 和 反编译器,你要哪个(歪头)? 我全都要(捏拳)!

    前言 从 C# 6.0 开始,C# 编译器就从以前由 C++ 实现的 csc.exe 换成了用 C# 重新实现的开放式 API 式编译服务 Roslyn.这个编译器到现在已经替代了老式编译器,从前 W ...

  2. Ubuntu查看与结束任务进程

    1.打开终端 2.敲  ps -ef  查出进程的编号(就是PID那列) 3.输入 kill PID 即可(如果PID是123456,则kill 123456) 例如: 我想把splash关闭,直接输 ...

  3. 第6/7Beta冲刺

    1.团队成员 成员姓名 成员学号 秦裕航 201731062432(组长) 刘东 201731062227 张旭 201731062129 王伟 201731062214 2.SCRU部分 2.1各成 ...

  4. MySQL 中的共享锁和排他锁的用法

    在 MySQL 中的行级锁.表级锁和页级锁中,咱们介绍过,行级锁是 MySQL 中锁定粒度最细的一种锁,行级锁能大大减少数据库操作的冲突.行级锁分为共享锁和排他锁两种,本文将详细介绍共享锁和排他锁的概 ...

  5. LeetCode 343. 整数拆分(Integer Break) 25

    343. 整数拆分 343. Integer Break 题目描述 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 每日一算法2019/5/2 ...

  6. 1.JVM前奏篇(看官网怎么说)

    JVM(Java Virtual Machine) 前奏篇(看官网规范怎么说) 1.The relation of JDK/JRE/JVM 在下图中,我们所接触的,最熟悉,也是经常打交道的 最顶层 J ...

  7. python基础 — 数据组合

    a = [1, 2, 3] b = [4, 5, 6] c = [7, 8, 9] for x, y, z in (a, b, c): print(x, y, x) print(type(zip(a, ...

  8. SQL学习-SQL Server

           

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

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

  10. Windows MySql增量备份、完整备份采坑之路

    1.前言 这周公司交给我一个任务,负责项目Mysql数据库的备份,因为项目上线后数据是一个大问题,出了什么问题数据才是最大的问题,备份这时候就显得尤为重要, 公司项目的思路是:在项目系统设置内可以勾选 ...