【BZOJ1396】识别子串
题面
http://darkbzoj.tk/problem/1396
题解
#include<cstdio> #include<iostream> #include<cstring> #include<vector> #define ri register int #define N 500050 using namespace std; vector<int> son[N<<1]; int n; int sum[N],ans[N]; struct Segment_tree{ int minv[N<<2]; void clear() { for (ri i=1;i<=4*n;i++) minv[i]=n; } void pushdown(int x) { if (minv[x]<minv[x<<1]) minv[x<<1]=minv[x]; if (minv[x]<minv[x<<1|1]) minv[x<<1|1]=minv[x]; } int query(int x,int lb,int rb,int loc) { if (lb==rb) return minv[x]; pushdown(x); int mid=(lb+rb)/2; if (loc<=mid) return query(x<<1,lb,mid,loc); else return query(x<<1|1,mid+1,rb,loc); } void change(int x,int lb,int rb,int l,int r,int k){ if (r<lb || l>rb) return; if (l<=lb && rb<=r) { minv[x]=min(k,minv[x]); return; } pushdown(x); int mid=(lb+rb)/2; change(x<<1,lb,mid,l,r,k); change(x<<1|1,mid+1,rb,l,r,k); } } t; struct SAM { int ff[N<<1],len[N<<1],cnt[N<<1]; int ch[N<<1][26]; int loc[N<<1]; int las,tot; void init() { las=tot=1; } void extend(int c,int la) { int np=++tot,p=las; las=tot; len[np]=len[p]+1; cnt[np]=1; loc[np]=la; while (p && !ch[p][c]) ch[p][c]=np,p=ff[p]; if (!p) ff[np]=1; else { int q=ch[p][c]; if (len[q]==len[p]+1) ff[np]=q; else { int nq=++tot; for (ri i=0;i<26;i++) ch[nq][i]=ch[q][i]; ff[nq]=ff[q]; len[nq]=len[p]+1; ff[np]=ff[q]=nq; while (p && ch[p][c]==q) ch[p][c]=nq,p=ff[p]; } } } void maketree(){ for (ri i=1;i<=tot;i++) son[ff[i]].push_back(i); } void treesum(int x){ for (ri i=0;i<son[x].size();i++) { treesum(son[x][i]); if (cnt[son[x][i]]) loc[x]=loc[son[x][i]]; cnt[x]+=cnt[son[x][i]]; } } void work(){ for (ri i=1;i<=tot;i++) if (cnt[i]==1) { t.change(1,1,n,loc[i]-len[ff[i]],loc[i],len[ff[i]]+1); sum[loc[i]-len[ff[i]]-1]++; sum[loc[i]-len[i]]--; } } } sam; char s[N]; int main(){ sam.init(); scanf("%s",s); n=strlen(s); for (ri i=0;i<n;i++) { sam.extend(s[i]-'a',i+1); } sam.maketree(); sam.treesum(1); t.clear(); sam.work(); for (ri i=1;i<=n;i++) { ans[i]=t.query(1,1,n,i); } for (ri i=n;i>=1;i--) { sum[i]+=sum[i+1]; if (sum[i]>0) { ans[i]=min(ans[i],ans[i+1]+1); } } for (ri i=1;i<=n;i++) printf("%d\n",ans[i]); }