题目大意:

给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次

神题

以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$节点

若令$fa=pre_{x},L=dep_{fa},R=dep_{x}$

1.对于以$i\in[1,R-L]$为开头,以$R$为结尾的串,合法串的长度是$R-i+1$

如果在$S_{1...x}$串中不断删去开头的字符,删到串剩余长度为$dep_{fa}$时结束

上述过程在$parent$树里的表现为,从表示串$S_{1...x}$的节点$a$,删掉最后一个字符后,跳到了表示$S_{x-dep_{fa}+1...x}$的节点$b$

不必考虑$b$的$right$集合大小,因为$R$是递增的,如果$b$节点的串能作为识别串,$a$节点的答案一定不如$b$优秀

所以我们干脆只讨论不跳到$b$的情况就行了

那么$i\in[1,R-L]$为开头,$R$为结尾的的串一定都能作为$[1,R-L]$的识别串

2.对于以$i\in[R-L+1,R]$为开头,以$R$为结尾的串,合法串的长度是$R-L+1$

一样的道理,如果从$a$跳到了$b$,$b$节点的串可能不合法,但$a$节点的串一定合法

那么以$L$为开头,$R$为结尾的的串一定都能作为$[1,R-L+1]$的识别串

区间修改,单点查询,开两颗线段树维护一下就好

 #include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 105000
#define S1 (N1<<1)
#define T1 (N1<<2)
#define ll long long
#define uint unsigned int
#define rint register int
#define il inline
#define inf 0x3f3f3f3f
#define idx(X) (X-'a')
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
char str[N1];
int len;
struct Seg{
int mi[S1<<];
void pushdown(int rt){
mi[rt<<]=min(mi[rt<<],mi[rt]);
mi[rt<<|]=min(mi[rt<<|],mi[rt]);}
void build(int l,int r,int rt)
{
mi[rt]=inf;
if(l==r) return;
int mid=(l+r)>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
}
void update(int L,int R,int l,int r,int rt,int w)
{
if(L<=l&&r<=R) {mi[rt]=min(w,mi[rt]);return;}
pushdown(rt);int mid=(l+r)>>;
if(L<=mid) update(L,R,l,mid,rt<<,w);
if(R>mid) update(L,R,mid+,r,rt<<|,w);
}
int query(int x,int l,int r,int rt)
{
if(l==r) return mi[rt];
pushdown(rt);int mid=(l+r)>>;
if(x<=mid) return query(x,l,mid,rt<<);
else return query(x,mid+,r,rt<<|);
}
}s1,s2;
namespace SAM{
int trs[S1][],pre[S1],dep[S1],ed[S1],sz[S1],tot,la;
void init(){tot=la=;}
void reduct(){la=;}
void insert(int c)
{
int p=la,np=++tot,q,nq;la=np;
dep[np]=dep[p]+;ed[np]=;
for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np;
if(!p) {pre[np]=;return;}
q=trs[p][c];
if(dep[q]==dep[p]+) pre[np]=q;
else{
pre[nq=++tot]=pre[q];
pre[q]=pre[np]=nq;
dep[nq]=dep[p]+;
memcpy(trs[nq],trs[q],sizeof(trs[q]));
for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq;
}
}
int hs[S1],que[S1],ans[N1];
void solve()
{
for(int i=;i<=tot;i++) hs[dep[i]]++;
for(int i=;i<=len;i++) hs[i]+=hs[i-];
for(int i=;i<=tot;i++) que[hs[dep[i]]--]=i;
int x,fx;
for(int i=tot-;i>;i--)
{
x=que[i];
sz[x]+=(ed[x]?:);
sz[pre[x]]+=sz[x];
}
s1.build(,tot,);
s2.build(,tot,);
for(int i=;i<=tot;i++)
{
x=que[i],fx=pre[x];
if(sz[x]>) continue;
if(dep[fx]>=) s1.update(dep[x]-dep[fx]+,dep[x],,tot,,dep[fx]+);
if(dep[fx]+<=dep[x]) s2.update(,dep[x]-dep[fx],,tot,,dep[x]);
}
for(int i=;i<=len;i++)
{
ans[i]=min(s1.query(i,,tot,),s2.query(i,,tot,)-i+);
printf("%d\n",ans[i]);
}
}
}; int main()
{
//freopen("t2.in","r",stdin);
scanf("%s",str+);
len=strlen(str+);
SAM::init();
for(int i=;i<=len;i++)
SAM::insert(idx(str[i]));
SAM::solve();
return ;
}

BZOJ 1396 识别子串 (后缀自动机+线段树)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. bzoj 1396/2865: 识别子串 后缀自动机+线段树

    水水的字符串题 ~ #include <map> #include <cstdio> #include <cstring> #include <algorit ...

随机推荐

  1. 批量删除.svn目录

    find . -type d -name ".svn"|xargs rm -rf find . -type d -iname ".svn" -exec rm - ...

  2. 《使用CSLA 2019:CSLA .NET概述》原版和机译文档下载

    自己从作者官方网站上(http://www.cslanet.com/)下载的免费版.PDF文档,又使用有道付款翻译的,供大家下载学习,文档中是对CSLA.NET4.9版本的介绍. 下载链接:http: ...

  3. BA-闭式冷却塔系统

  4. C#高级编程八十三天----程序集的含义

    程序集的含义 一.程序集是包括一个或多个类型定义文件和资源文件的集合.它同意我们分析可重用类型的逻辑表示和物理表示. 相当于你定义了一个项目XXProject,项目存在非常多文件(类,窗口,接口,资源 ...

  5. MySql 基础学习笔记 1——概述与基本数据类型: 整型: 1)TINYINT 2)SMALLINT 3) MEDIUMINT 4)INT 5)BIGINT 主要是大小的差别 图 浮点型:命令

    一.CMD中经常使用mysql相关命令 mysql -D, --database=name  //打开数据库 --delimiter=name  //指定分隔符 -h, --host=name  // ...

  6. JAVA程序设计(11)-----面对对象0基础设计 麻将 创建麻将牌 然后洗牌 发牌~ 恩 就这样

    zzzzZZZZ 1.開始还想贴图的 实在太懒了-- 这是一张麻将 package com.lovo; import java.awt.Graphics; import java.awt.Image; ...

  7. C语言之函数调用11—递归法求Hermite函数

    /*递归法! ========================================== 题目: Hermite 函数:输入n.x,求Hn(x)? H0(x)=1; H1(x)=2*x; H ...

  8. 浅析Context Class Loader

    浅析Context Class Loader 2010-05-11 16:58:49 分类: Java 转载自 薛笛的专栏http://blog.csdn.net/kabini/archive/200 ...

  9. Blur 算法 (Unity 5.0 Shader)

    一:简单 Blur 算法 一个像素的颜色值由其邻近的若干像素和自己的颜色值的平均值重新定义,以此达到模糊的效果. 如下图,红色的像素点的值将由它和它周围的24个像素的平均值重新定义.计算的范围一般由一 ...

  10. 【DataStructure】One of queue usage: Simulation System

    Statements: This blog was written by me, but most of content  is quoted from book[Data Structure wit ...