BZOJ-1396: 識別子串
阿新 • • 發佈:2018-12-04
字尾自動機+線段樹
先建出\(sam\),統計一遍每個點的\(right\)集合大小\(siz\),對於\(siz=1\)的點\(x\),他所代表的子串只會出現一次,設\(y=fa[x]\),則這個點代表的子串即為\((1...len[x]-len[y],len[x])\),對於子串\((len[x]-len[y],len[x])\)的每一個點,這個子串都是他的識別子串,長度固定\(len[y]+1\),而對於一個點\(i\in[1,len[x]-len[y]-1]\),子串\((i,len[x])\)一定是他的一個識別子串,長度\(len[x]+1-i\)。可以用兩棵線段樹分別存\(len[y]+1\)
#include<map> #include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=2e5+100; struct xdt{ int poi[maxn<<2],lazy[maxn<<2]; void updata(int x){ poi[x]=min(poi[x<<1],poi[x<<1|1]); } void pushdown(int x){ if(!lazy[x]) return; poi[x<<1]=min(poi[x<<1],lazy[x]); lazy[x<<1]=lazy[x<<1]?min(lazy[x<<1],lazy[x]):lazy[x]; poi[x<<1|1]=min(poi[x<<1|1],lazy[x]); lazy[x<<1|1]=lazy[x<<1|1]?min(lazy[x<<1|1],lazy[x]):lazy[x]; lazy[x]=0; } void build(int l,int r,int now){ poi[now]=0x7fffffff; if(l==r) return; int mid=l+r>>1; build(l,mid,now<<1); build(mid+1,r,now<<1|1); } void revise(int lc,int rc,int l,int r,int now,int z){ if(lc==l&&rc==r){ poi[now]=min(poi[now],z); if(lazy[now]==0) lazy[now]=z; else lazy[now]=min(lazy[now],z); return; } pushdown(now); int mid=lc+rc>>1; if(l<=mid) revise(lc,mid,l,min(mid,r),now<<1,z); if(r>mid) revise(mid+1,rc,max(mid+1,l),r,now<<1|1,z); updata(now); } int query(int lc,int rc,int x,int now){ if(lc==rc) return poi[now]; pushdown(now); int mid=lc+rc>>1; if(x<=mid) return query(lc,mid,x,now<<1); else return query(mid+1,rc,x,now<<1|1); } }t1,t2; struct SAM{ int son[maxn][26],len[maxn],siz[maxn],fa[maxn],tax[maxn],a[maxn]; int tot,last,n; char s[maxn]; void insert(int x){ int p=last,np=++tot; len[np]=len[p]+1; siz[np]=1; while(~p&&!son[p][x]) son[p][x]=np,p=fa[p]; if(p==-1) fa[np]=0; else{ int q=son[p][x]; if(len[q]==len[p]+1) fa[np]=q; else{ int nq=++tot; memcpy(son[nq],son[q],sizeof(son[q])); fa[nq]=fa[q]; len[nq]=len[p]+1; fa[q]=fa[np]=nq; while(~p&&son[p][x]==q) son[p][x]=nq,p=fa[p]; } } last=np; } void Qsort(){ for(int i=0;i<=n;i++) tax[i]=0; for(int i=1;i<=tot;i++) tax[len[i]]++; for(int i=1;i<=n;i++) tax[i]+=tax[i-1]; for(int i=1;i<=tot;i++) a[tax[len[i]]--]=i; } void ycl(){ last=tot=0,fa[0]=-1; for(int i=1;i<=n;i++) insert(s[i]-'a'); Qsort(); for(int i=tot;i>=1;i--) siz[fa[a[i]]]+=siz[a[i]]; t1.build(1,n,1),t2.build(1,n,1); for(int i=1;i<=tot;i++) if(siz[i]==1){ int l=len[i]-len[fa[i]],r=len[i]; t1.revise(1,n,l,r,1,r-l+1); // printf("->%d\n",t1.query(1,n,2,1)); if(l!=1) t2.revise(1,n,1,l-1,1,r+1); } } void query(){ // printf("->%d\n",t1.query(1,n,2,1)); for(int i=1;i<=n;i++) printf("%d\n",min(t1.query(1,n,i,1),t2.query(1,n,i,1)-i)); } }sam; int main(){ // freopen(".in","r",stdin); scanf("%s",sam.s+1),sam.n=strlen(sam.s+1); sam.ycl(); sam.query(); return 0; }