bzoj 1396 识别子串 后缀树+线段树
题目大意
给定一个长度\(\le100000\)的字符串
求每一个位置的最短识别子串
对于位置\(x\),能识别子串\(s[i...j]\)的条件是
1.\(i\le x \le j\)
2.\(s[i...j]\)在原串中只出现了一次
分析
从第二个条件入手
仅出现一次子串就是后缀树上\(|right|=1\)的子串
考虑贡献
该后缀左端点在\(left\)
长度范围\([L,R]\)
如图
对于\(A\)部分贡献的最短串长度为\(L\)
对于\(B\)部分贡献是等差数列\(i-lef+1\),提出\(1-lef\)
对上面分两棵线段树维护即可
solution
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
const int M=200007;
const int INF=1e9+7;
struct edge{int y,nxt;};
struct vec{
int g[M],te;
edge e[M];
vec(){memset(g,0,sizeof(g));te=0;}
void clear(){memset(g,0,sizeof(g));te=0;}
inline void push(int x,int y){e[++te].y=y;e[te].nxt=g[x];g[x]=te;}
inline int& operator () (int x){return g[x];}
inline edge& operator [] (int x){return e[x];}
}go;
char s[M];
int n;
int ch[M][26];
int stp[M],fa[M];
int lef[M];
int last,tot;
int ans[M];
struct Seg{
int tag;
Seg(){tag=INF;}
}seg1[262147],seg2[262147];
int newnode(int ss){
stp[++tot]=ss;
return tot;
}
int ext(int p,int q,int d){
int nq=newnode(stp[p]+1);
fa[nq]=fa[q]; fa[q]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;p&&ch[p][d]==q;p=fa[p]) ch[p][d]=nq;
return nq;
}
int sam(int p,int d){
int np=ch[p][d];
if(np) return (stp[p]+1==stp[np]) ? np : ext(p,np,d);
np=newnode(stp[p]+1);
for(;p&&!ch[p][d];p=fa[p]) ch[p][d]=np;
if(!p) fa[np]=1;
else{
int q=ch[p][d];
fa[np]= (stp[p]+1==stp[q]) ? q : ext(p,q,d);
}
return np;
}
void mdf(Seg *S,int x,int l,int r,int tl,int tr,int d){
if(S[x].tag<=d) return;
if(tl<=l&&r<=tr) {S[x].tag=d;return;}
int mid=l+r>>1;
if(tl<=mid) mdf(S,x<<1,l,mid,tl,tr,d);
if(mid<tr) mdf(S,x<<1|1,mid+1,r,tl,tr,d);
}
void get(Seg *S,int x,int l,int r,int nw,int kd){
nw=min(nw,S[x].tag);
if(l==r){
if(kd==0) ans[l]=min(ans[l],nw);
else ans[l]=min(ans[l],l+nw);
return;
}
int mid=l+r>>1;
get(S,x<<1,l,mid,nw,kd);
get(S,x<<1|1,mid+1,r,nw,kd);
}
void dfs(int x){
int p,y;
for(p=go(x);p;p=go[p].nxt){
y=go[p].y;
dfs(y);
if(lef[y]){
if(lef[x]==0) lef[x]=lef[y];
else if(lef[x]>0) lef[x]=-1;
}
}
if(lef[x]>0){//if only one lef
int L=stp[fa[x]]+1;
int R=stp[x];
mdf(seg1,1,1,n,lef[x],lef[x]+L-1, L);
if(L!=R) mdf(seg2,1,1,n,lef[x]+L,lef[x]+R-1, 1-lef[x]);
}
}
int main(){
int i;
scanf("%s",s+1);
n=strlen(s+1);
last=tot=1;
for(i=n;i>0;i--){
last=sam(last,s[i]-'a');
lef[last]=i;
}
for(i=2;i<=tot;i++) go.push(fa[i],i);
dfs(1);
for(i=1;i<=n;i++) ans[i]=INF;
get(seg1,1,1,n,INF,0);
get(seg2,1,1,n,INF,1);
for(i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}