题目大意:

给你一个字符串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. 更新时间戳.txt

    UPDATE bbs2 INNER JOIN time1 ON bbs2.AnnounceID = time1.AnnounceID SET bbs2.asptime = time1.asptime

  2. android onConfigurationChanged的那点事

    Android学习笔记——关于onConfigurationChanged   从事Android开发,免不了会在应用里嵌入一些广告SDK,在嵌入了众多SDK后,发现几乎每个要求在AndroidMan ...

  3. 【hihocoder 1312】搜索三·启发式搜索(启发式搜索写法)

    [题目链接]:http://hihocoder.com/problemset/problem/1312?sid=1092363 [题意] [题解] 定义一个A*函数 f = step+val 这里的v ...

  4. 【explain】MySQL联表查询中的驱动表

    写在前面 1.不要求每个人一定理解 联表查询(join/left join/inner join等)时的mysql运算过程 2.不要求每个人一定知道线上(现在或未来)哪张表数据量大,哪张表数据量小 3 ...

  5. 使用githug游戏提高git水平

  6. 2015 Multi-University Training Contest 2 1006 Friends 壮压

    题目链接 题意:t 组測试数据,每组測试数据有 n个人,m条关系 每条关系能够是 "线上关系" 或者 "线下关系". 要求每一个人的线上关系(条数) == 线下 ...

  7. Openwrt 软件安装源

    进入http://downloads.openwrt.org/barrier_breaker/14.07/站点找到符合处理器型号的软件源.參考下图: watermark/2/text/aHR0cDov ...

  8. SOA概念具体解释

    1.概述 1.1基本定义 SOA(Service-Oriented Architecture)既面向服务的体系结构,是一个组件模型.它将应用程序猿的不同功能可是(称为服务)通过定义良好的接口联系起来. ...

  9. ZOJ 2913 Bus Pass (近期的最远BFS HDU2377)

    题意  在全部城市中找一个中心满足这个中心到全部公交网站距离的最大值最小 输出最小距离和满足最小距离编号最小的中心 最基础的BFS  对每一个公交网站BFS  dis[i]表示编号为i的点到全部公交网 ...

  10. 2015.06.11,技术,关于Matlab中的Jbtest检验

    总体分布的正态性检验一般采取Jarque-Bera检验方法. 1. JBTest检验的定义: 在统计学中,Jarque-Bera检验是对样本数据是否具有符合正态分布的偏度和峰度的拟合优度的检验.该检验 ...