博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2018.12.23 bzoj2865&&1396: 字符串识别(后缀自动机+线段树)
阅读量:4507 次
发布时间:2019-06-08

本文共 2790 字,大约阅读时间需要 9 分钟。

卡空间差评!
题意简述:给一个字串,对于每个位置求出经过这个位置且只在字串中出现一次的子串的长度的最小值。


解法:先建出samsamsam,显然只有当sizep=1size_p=1sizep=1的时候才对答案有贡献。

于是对于每个sizep=1size_p=1sizep=1的状态分情况更新答案。

  1. pos=[pos[p]−len[link[p]]+1,pos[p]]pos=[pos[p]-len[link[p]]+1,pos[p]]pos=[pos[p]len[link[p]]+1,pos[p]],那么ansi=min{ansi,lenlinkp+1}ans_i=min\{ans_i,len_{link_p}+1\}ansi=min{
    ansi,lenlinkp+
    1}
  2. pos=[pos[p]−len[p]+1,pos[p]−len[link[p]]]pos=[pos[p]-len[p]+1,pos[p]-len[link[p]]]pos=[pos[p]len[p]+1,pos[p]len[link[p]]],那么ansi=min{ansi,lenp−i+1}ans_i=min\{ans_i,len_p-i+1\}ansi=min{
    ansi,lenp
    i+1}

第一类直接上线段树。

第二类?我们令fi=ansi+if_i=ans_i+ifi=ansi+i,用线段树维护fif_ifi的值最后统计答案的时候减去iii即可。
代码:

#include
#define ri register int#define lc (p<<1)#define rc (p<<1|1)#define mid (l+r>>1)using namespace std;inline int read(){
int ans=0; char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans; }const int N=9e5+5;int n,ans[500005];char s[N];struct SGT{
int mn[N<<1]; inline void build(int p,int l,int r,int f){
mn[p]=0x3f3f3f3f; if(l==r){
mn[p]=f?n+l:n;return;} build(lc,l,mid,f),build(rc,mid+1,r,f); } inline void update(int p,int l,int r,int ql,int qr,int v){
if(ql>r||qr
mid)update(rc,mid+1,r,ql,qr,v); else update(lc,l,mid,ql,mid,v),update(rc,mid+1,r,mid+1,qr,v); } inline void query(int p,int l,int r,int f){
if(l==r){
ans[l]=min(ans[l],mn[p]-f*l);return;} mn[lc]=min(mn[lc],mn[p]),query(lc,l,mid,f); mn[rc]=min(mn[rc],mn[p]),query(rc,mid+1,r,f); }}T1,T2;struct SAM{
int last,tot,len[N],link[N],son[N][26],siz[N],rk[N],cnt[500005],pos[N]; SAM(){
last=tot=1,len[0]=-1;} inline void expand(int x,int id){
int p=last,np=++tot; siz[last=np]=1,pos[np]=id,len[np]=len[p]+1; while(p&&!son[p][x])son[p][x]=np,p=link[p]; if(!p){
link[np]=1;return;} int q=son[p][x],nq; if(len[q]==len[p]+1){
link[np]=q;return;} len[nq=++tot]=len[p]+1,memcpy(son[nq],son[q],sizeof(son[q])),link[nq]=link[q],link[q]=link[np]=nq; while(p&&son[p][x]==q)son[p][x]=nq,p=link[p]; } inline void solve(){
for(ri i=1;i<=tot;++i)++cnt[len[i]]; for(ri i=1;i<=n;++i)cnt[i]+=cnt[i-1]; for(ri i=1;i<=tot;++i)rk[cnt[len[i]]--]=i; T1.build(1,1,n,0),T2.build(1,1,n,1); for(ri i=tot,p;i;--i){
p=rk[i]; if(siz[p]==1){
T1.update(1,1,n,pos[p]-len[link[p]]+1,pos[p],len[link[p]]+1); T2.update(1,1,n,pos[p]-len[p]+1,pos[p]-len[link[p]],len[p]+1); } siz[link[p]]+=siz[p],pos[link[p]]=max(pos[link[p]],pos[p]); } fill(ans+1,ans+n+1,n+1); T1.query(1,1,n,0),T2.query(1,1,n,1); for(ri i=1;i<=n;++i)cout<
<<'\n'; }}sam;int main(){
scanf("%s",s+1),n=strlen(s+1); for(ri i=1;i<=n;++i)sam.expand(s[i]-'a',i); sam.solve(); return 0;}

转载于:https://www.cnblogs.com/ldxcaicai/p/10367807.html

你可能感兴趣的文章
flask 第四篇 模板语言jinja2
查看>>
非均衡分类问题的思考与问题与解决思路
查看>>
头文件与extern
查看>>
python开发技术详解(三) 进阶的语法
查看>>
LeetCode Missing Number
查看>>
Linux 网络(连接)相关参数作用
查看>>
鼠标事件先后顺序
查看>>
洛谷P2756 飞行员配对方案问题
查看>>
在java中删除数组元素的练习
查看>>
[No0000B7]If else 与 三元表达式? : 效率对比
查看>>
【PSR规范专题(5)】PSR-4 改进后的自动加载规范
查看>>
01单例模式(创建型模式)
查看>>
Java 组播
查看>>
java_泛型,设置类型通配符的上限
查看>>
内存保护机制及绕过方案——通过覆盖虚函数表绕过/GS机制
查看>>
并不对劲的fhq treap
查看>>
Ubuntu环境下使用npm编译从git上clone下来的前端(Javascript)项目
查看>>
[JavaEE,MVC] Struts工作原理
查看>>
[MySQL] 统计函数记录
查看>>
随想 20180530
查看>>