题目大意
给定一个字符串,求对于每一个位置,求包含它的只出现一次的子串的最短长度。
题解
先建后缀自动机,对于每一个$|Endpos|=1$的节点,设其右端点为$r$。
对于所有$x\in [r-minlen+1,r]$,可以用$minlen$的长度更新答案。
对于所有$x\in [r-maxlen+1,r-minlen]$,可以用$r-x$的长度更新。
用线段树维护两个标记,一个用来更新能够覆盖答案的最小长度$minlen$,即情况一,另一个用来更新能够用来更新答案的最左的右端点$r$,即情况二。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
using namespace std;
namespace IO{
const int BS=(1<<20); int Top=0;
char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return *HD++;}
void flush(){fwrite(OT,1,OS-OT,stdout);}
void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
void write(int x){
if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
while(x) SS[++Top]=x%10,x/=10;
while(Top) Putchar(SS[Top]+'0'),--Top; Putchar('\n');
}
int read(){
int nm=0,fh=1; char cw=Getchar();
for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
}
using namespace IO;
char S[M]; int n;
namespace segtree{
int tg[M<<1][2];
void init(){memset(tg,0x3f,sizeof(tg));}
void mdf(int x,int l,int r,int L,int R,int dt,int kd){
if(L<=l&&r<=R){tg[x][kd]=min(dt,tg[x][kd]);return;}
if(r<L||R<l) return; int mid=((l+r)>>1);
mdf(x<<1,l,mid,L,R,dt,kd),mdf(x<<1|1,mid+1,r,L,R,dt,kd);
}
void qry(int x,int l,int r,int ps,int len){
ps=min(ps,tg[x][0]),len=min(len,tg[x][1]);
if(l==r){write(min(ps-l+1,len));return;} int mid=((l+r)>>1);
qry(x<<1,l,mid,ps,len),qry(x<<1|1,mid+1,r,ps,len);
}
}
namespace SAM{
int len[M],rs[M],fa[M],t[M][26],F[M],C[M],T[M];
int now,cnt,ed,vs[M],sz[M],ps[M];
void init(){cnt=ed=1,now=0,memset(rs,-1,sizeof(rs));}
void ins(int c){
int x=ed; len[ed=++cnt]=++now,rs[ed]=now,sz[ed]=1;
while(x&&!t[x][c]) t[x][c]=ed,x=fa[x];
if(!x){fa[ed]=1;return;} int y=t[x][c];
if(len[y]==len[x]+1){fa[ed]=y;return;}
len[++cnt]=len[x]+1,fa[cnt]=fa[y],fa[y]=fa[ed]=cnt;
memcpy(t[cnt],t[y],sizeof(t[y]));
while(x&&t[x][c]==y) t[x][c]=cnt,x=fa[x];
}
void build(){
for(int i=1;i<=cnt;i++) C[len[i]]++;
for(int i=1;i<=n;i++) C[i]+=C[i-1];
for(int i=1;i<=cnt;i++) T[C[len[i]]--]=i;
for(int i=cnt;i>0;i--){
int x=T[i]; sz[fa[x]]+=sz[x];
if(sz[x]) rs[fa[x]]=rs[x]; if(sz[x]>1||!sz[x]) continue;
segtree::mdf(1,1,n,rs[x]-len[fa[x]],rs[x],len[fa[x]]+1,1);
segtree::mdf(1,1,n,rs[x]-len[x]+1,rs[x]-len[fa[x]]-1,rs[x],0);
}
}
}
int main(){
scanf("%s",S+1),n=strlen(S+1),SAM::init();
for(int i=1;i<=n;i++) SAM::ins(S[i]-'a');
segtree::init(),SAM::build();
segtree::qry(1,1,n,M,M),flush();return 0;
}