1. 程式人生 > >BZOJ.1396.識別子串(後綴自動機/後綴數組 線段樹)

BZOJ.1396.識別子串(後綴自動機/後綴數組 線段樹)

www geo HR printf -- ring strlen mod HA

題目鏈接

SAM:能成為識別子串的只有那些|right|=1的節點代表的串。
設這個節點對應原串的右端點為r[i],則如果|right[i]|=1,即s[ [r[i]-len[i]+1,r[i]-len[fa[i]]] ~ r[i] ]這些子串都出現一次。
那麽對於[r[i]-len[i]+1, r[i]-len[fa[i]]]都可以用此時對應的長度(r-i+1)更新其最小值(這個維護每個位置最小的r就可以)。
對於位置[r[i]-len[fa[i]]+1, r[i]可以用len[fa[i]]+1更新(這個直接維護最小值)。
所以建兩棵線段樹就可以了。

SA:在整個串中不重復出現,我們能想到height。對於一個位置i,以它為左端點能形成的最短的不重復出現串長度l=max(ht[i],ht[i+1])+1.

那麽i能對區間i~i+l-2貢獻l;包含i的子串長度>l時一定也只出現了一次,即可以對i+l-1~n貢獻對應長度(p-i+1)的值。還是用線段樹維護。

l==r的時候不能PushDown啊mdzz。

//32176kb   928ms
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=1e5+5,INF=1061109554;

struct Segment_Tree
{
    #define lson rt<<1
    #define rson rt<<1|1
#define ToL l,m,rt<<1 #define ToR m+1,r,rt<<1|1 int mn[N<<2],tag[N<<2]; Segment_Tree(){ memset(mn,0x3f,sizeof mn), memset(tag,0x3f,sizeof tag); } inline void PushUp(int rt){ mn[rt]=std::min(mn[lson],mn[rson]); } inline void Update(int
x,int v){ tag[x]=std::min(tag[x],v), mn[x]=std::min(mn[x],v); } inline void PushDown(int rt){ Update(lson,tag[rt]), Update(rson,tag[rt]), tag[rt]=INF; } void Modify(int l,int r,int rt,int L,int R,int v) {//線段樹都沒一次寫對→_→ if(L>R) return; if(L<=l && r<=R){ tag[rt]=std::min(tag[rt],v), mn[rt]=std::min(mn[rt],v); return; } if(tag[rt]<INF) PushDown(rt); int m=l+r>>1; if(L<=m) Modify(ToL,L,R,v); if(m<R) Modify(ToR,L,R,v); // PushUp(rt); } }t1,t2; struct Suffix_Automaton { #define S N<<1 int tot,las,fa[S],son[S][26],len[S],R[S],right[S],A[S],tm[S]; char s[N]; void Insert(int pos,int c) { int p=las,np=++tot; len[las=np]=len[p]+1, R[np]=pos, right[np]=1; for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np; if(!p) fa[np]=1; else { int q=son[p][c]; if(len[q]==len[p]+1) fa[np]=q; else { int nq=++tot; len[nq]=len[p]+1; memcpy(son[nq],son[q],sizeof son[q]); fa[nq]=fa[q], fa[q]=fa[np]=nq; for(; son[p][c]==q; p=fa[p]) son[p][c]=nq; } } } int Build() { las=tot=1, scanf("%s",s+1); int l=strlen(s+1); for(int i=1; i<=l; ++i) Insert(i,s[i]-'a'); for(int i=1; i<=tot; ++i) ++tm[len[i]]; for(int i=1; i<=l; ++i) tm[i]+=tm[i-1]; for(int i=1; i<=tot; ++i) A[tm[len[i]]--]=i; for(int i=tot,x=A[tot],f,p; i; x=A[--i]) { right[fa[x]]+=right[x];// R[fa[x]]=R[x]; if(right[x]==1) f=fa[x], p=R[x], t1.Modify(1,l,1,p-len[f]+1,p,len[f]+1), t2.Modify(1,l,1,p-len[x]+1,p-len[f],p); } return l; } }sam; void Query(int l,int r,int rt) { if(l==r) printf("%d\n",std::min(t1.mn[rt],t2.mn[rt]-l+1)); else { if(t1.tag[rt]<INF) t1.PushDown(rt); if(t2.tag[rt]<INF) t2.PushDown(rt); Query(l,l+r>>1,rt<<1), Query((l+r>>1)+1,r,rt<<1|1); } } int main() { int n=sam.Build(); Query(1,n,1); return 0; }

BZOJ.1396.識別子串(後綴自動機/後綴數組 線段樹)