https://www.lydsy.com/JudgeOnline/problem.php?id=1396

后缀自动机的parent树上,如果不是叶子节点,那么至少有两个子节点

而一个状态所代表子串的出现次数就是子树中叶子节点的个数

所以只有叶子节点 即 |Right|=1的状态 代表的子串 出现了1次

我们计算以每一个位置为子串右端点时,它对一些位置的贡献

枚举|Right|=1的状态s

令end=Right(s)

那么以end为子串右端点,长度在[1,Max(parent(s))]的子串至少还会在s的父节点表示的状态中出现

所以在以end为识别子串右端点时

位置[end-Max(parent(s)),end]的最短长度为Max(parent(s)+1

位置[end-Max(s)+1,end-Max(parent(s))]的最短长度为 end-i+1

用两棵线段树维护

一棵直接维护最小值

另一棵维护end+1的最小值,查询的时候将结果-i

#include<cstdio>
#include<cstring>
#include<algorithm> #define N 100001 using namespace std; char s[N]; int ch[N<<][],tot=;
int fa[N<<],len[N<<];
int siz[N<<];
int last=,p,q,np,nq; int leaf[N]; int v[N],sa[N<<]; struct Segment
{
int mx[N<<];
int tag[N<<]; void down(int k)
{
mx[k<<]=min(mx[k<<],tag[k]);
mx[k<<|]=min(mx[k<<|],tag[k]);
tag[k<<]=min(tag[k<<],tag[k]);
tag[k<<|]=min(tag[k<<|],tag[k]);
tag[k]=2e9;
} void build(int k,int l,int r)
{
mx[k]=tag[k]=2e9;
if(l==r) return;
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
} void change(int k,int l,int r,int opl,int opr,int w)
{
if(l>=opl && r<=opr)
{
mx[k]=min(mx[k],w);
tag[k]=min(tag[k],w);
return;
}
int mid=l+r>>;
if(tag[k]!=2e9) down(k);
if(opl<=mid) change(k<<,l,mid,opl,opr,w);
if(opr>mid) change(k<<|,mid+,r,opl,opr,w);
mx[k]=min(mx[k<<],mx[k<<|]);
} int query(int k,int l,int r,int x)
{
if(l==r) return mx[k];
int mid=l+r>>;
if(tag[k]!=2e9) down(k);
if(x<=mid) return query(k<<,l,mid,x);
return query(k<<|,mid+,r,x);
}
}; Segment tr1,tr2; void extend(int c)
{
len[np=++tot]=len[last]+;
siz[tot]=;
for(p=last;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=;
else
{
q=ch[p][c];
if(len[q]==len[p]+) fa[np]=q;
else
{
nq=++tot;
fa[nq]=fa[q];
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[q]=fa[np]=nq;
len[nq]=len[p]+;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
last=np;
} int main()
{
scanf("%s",s+);
int n=strlen(s+);
for(int i=;i<=n;++i)
{
leaf[i]=tot+;
extend(s[i]-'a');
}
for(int i=;i<=tot;++i) v[len[i]]++;
for(int i=;i<=n;++i) v[i]+=v[i-];
for(int i=;i<=tot;++i) sa[v[len[i]]--]=i;
int x;
for(int i=tot;i;--i)
{
x=sa[i];
siz[fa[x]]+=siz[x];
}
tr1.build(,,n);
tr2.build(,,n);
int l,r,end;
for(int x=;x<=tot;++x)
if(siz[x]==)
{
l=len[fa[x]];
r=len[x];
end=len[x];
tr1.change(,,n,end-l,end,l+);
tr2.change(,,n,end-r+,end-l,end+);
}
int a,b;
for(int i=;i<=n;++i)
{
a=tr1.query(,,n,i);
b=tr2.query(,,n,i)-i;
printf("%d\n",min(a,b));
}
return ;
}

bzoj千题计划318:bzoj1396: 识别子串(后缀自动机 + 线段树)的更多相关文章

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

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

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

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

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

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

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

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

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

    题目大意: 给你一个字符串S,求关于每个位置x的识别串T的最短长度,T必须满足覆盖x,且T在S中仅出现一次 神题 以节点x为结尾的识别串,必须满足它在$parent$树的子树中只有一个$endpos$ ...

  6. bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)

    https://www.lydsy.com/JudgeOnline/problem.php?id=5017 暴力: 对于每一个炸弹,枚举所有的炸弹,看它爆炸能不能引爆那个炸弹 如果能,由这个炸弹向引爆 ...

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

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

  8. bzoj1396识别子串(SAM+线段树)

    复习SAM板子啦!考前刷水有益身心健康当然这不是板子题/水题…… 很容易发现只在i位置出现的串一定是个前缀串.那么对答案的贡献分成两部分:一部分是len[x]-fa~len[x]的这部分贡献会是r-l ...

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

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

随机推荐

  1. rt-thread之 for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++) 理解

    @2019-01-30 [小记] 利用宏 INIT_EXPORT() --- __attribute__() 将函数重新放置在自定义段,执行时去该段获取函数地址 RT-Thread 的 INIT_BO ...

  2. Mysql连接报错:1130 - Host ‘118.111.111.111’ is not allowed to connect to this MariaDB server

    这个问题是因为在数据库服务器中的mysql数据库中的user的表中没有权限(也可以说没有用户),下面将记录我遇到问题的过程及解决的方法. 在搭建完LNMP环境后用Navicate连接出错 遇到这个问题 ...

  3. Age of Moyu HDU - 6386 (杭电多校7A)

    给出n和点,m条边,每条边有各自的标号,进入第一个标号需要消耗1的费用,此后转换标号需要1费用,在同一个标号上走不需要费用.问你从1到n最少需要多少费用. 最短路变形,把第一个点看成不存在的标号,然后 ...

  4. staitc

    一.static和非static变量 1. static 修饰的变量称为类变量或全局变量或成员变量,在类被加载的时候成员变量即被初始化,与类关联,只要类存在,static变量就存在.非static修饰 ...

  5. Spring乱码问题解决方案

    请求乱码 GET请求乱码: 原因:请求参数带在url地址上.url地址什么时候解析? tomcat收到请求对url进行编解码(ISO8859-1) 解决方案:在tomcat的8080端口配置出加上 U ...

  6. Linux服务器SSH免密互访

    1.编辑Hosts文件: [root@yqtrack-elk01 /]# vim /etc/hosts

  7. 用foobar进行码率转换 适用与sacd-r转成低码率

    之前下载了不少高清音频,有黑胶转录的也有母带文件.这些高清音频大都是24bit,采样率96khz或者88.2khz或者更高.而我想将部分精品专辑刻录成cd.首先我需要将这些文件转换为16bit,44. ...

  8. C# DateTimePicker控件获取他的年,月,日,时,分,秒

    CustomFormat属性设置为: yyyy-MM-dd HH:mm:ss 记住还要修改一个属性值,DateFormat属性 可选项改为Custom,默认是Long

  9. 【UOJ 351】新年的叶子

    http://uoj.ac/problem/351 其实原来看到这题是真的不想做的 毕竟真的特别怕期望题 后来莫名发现自己打了正解 也是很震惊的2333 Description   对于一棵树,每次随 ...

  10. gethostbyname(domain) 老是返回 NULL, 凌乱了

    struct hostent *h = gethostbyname(pDomain); 今天在写一个下载网上文件到本地的小程序,在测试时发现 gethostbyname()老是返回NULL. 解析不了 ...