【后缀自动机例题】
学习笔记戳这里: 折跃
论文戳这里: 折跃
论文中的例题:
SPOJ NSUBSTR - Substrings
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 2500010 int N,a[MAXN],dp[MAXN],st[MAXN],Right[MAXN<<1],id[MAXN<<1]; char s[MAXN]; namespace SAM { int son[MAXN<<1][27],len[MAXN<<1],par[MAXN<<1]; int sz,last,root; inline void Init() {root=sz=last=1;} inline void Extend(int c) { int cur=++sz,p=last; len[cur]=len[p]+1; while (p && !son[p][c]) son[p][c]=cur,p=par[p]; if (!p) par[cur]=root; else { int q=son[p][c]; if (len[p]+1==len[q]) par[cur]=q; else { int nq=++sz; memcpy(son[nq],son[q],sizeof(son[nq])); par[nq]=par[q]; len[nq]=len[p]+1; while (p && son[p][c]==q) son[p][c]=nq,p=par[p]; par[cur]=par[q]=nq; } } last=cur; } inline void Build() {Init(); for (int i=1; i<=N; i++) Extend(a[i]=s[i]-'a'+1);} }using namespace SAM; int main() { scanf("%s",s+1); N=strlen(s+1); SAM::Build(); for (int i=1,now=root; i<=N; i++) now=son[now][a[i]],Right[now]++; for (int i=1; i<=sz; i++) st[len[i]]++; for (int i=1; i<=N; i++) st[i]+=st[i-1]; for (int i=1; i<=sz; i++) id[st[len[i]]--]=i; for (int i=sz; i>=1; i--) Right[par[id[i]]]+=Right[id[i]]; for (int i=1; i<=sz; i++) dp[len[i]]=max(dp[len[i]],Right[i]); for (int i=N; i>=1; i--) dp[i-1]=max(dp[i-1],dp[i]); for (int i=1; i<=N; i++) printf("%d\n",dp[i]); return 0; }
SPOJ SUBLEX - Lexicographical Substring Search
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define MAXN 900010 char A[MAXN],ans[MAXN]; int N,Q,K; namespace SAM { int son[MAXN<<1][27],par[MAXN<<1],len[MAXN<<1],root,last,sz; inline void Init() {root=sz=last=1;} inline void Extend(int c) { int cur=++sz,p=last; len[cur]=len[p]+1; while (p && !son[p][c]) son[p][c]=cur,p=par[p]; if (!p) par[cur]=root; else { int q=son[p][c]; if (len[p]+1==len[q]) par[cur]=q; else { int nq=++sz; memcpy(son[nq],son[q],sizeof(son[nq])); len[nq]=len[p]+1; par[nq]=par[q]; while (p && son[p][c]==q) son[p][c]=nq,p=par[p]; par[cur]=par[q]=nq; } } last=cur; } inline void Build() {Init(); for (int i=1; i<=N; i++) Extend(A[i]-'a'+1);} int st[MAXN],id[MAXN<<1],sum[MAXN<<1]; inline void Pre() { for (int i=1; i<=sz; i++) st[len[i]]++; for (int i=1; i<=N; i++) st[i]+=st[i-1]; for (int i=1; i<=sz; i++) id[st[len[i]]--]=i; for (int i=sz,Sum=0; i>=1; i--,Sum=0) { for (int j=1; j<=26; j++) Sum+=sum[son[id[i]][j]]; sum[id[i]]=Sum+1; } } inline void Query(int K) { int now=root,tot=0; while (K) { for (int i=1; i<=26; i++) if (son[now][i]) if (sum[son[now][i]]>=K) { ans[++tot]='a'+i-1,K--,now=son[now][i]; break; } else K-=sum[son[now][i]]; } ans[++tot]=0; } }using namespace SAM; int main() { scanf("%s",A+1); N=strlen(A+1); SAM::Build(); SAM::Pre(); scanf("%d",&Q); while (Q--) scanf("%d",&K),Query(K),puts(ans+1); return 0; }
SPOJ LCS - Longest Common Substring
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define MAXN 250010 char A[MAXN],B[MAXN]; int N,M; namespace SAM { int son[MAXN<<1][27],par[MAXN<<1],len[MAXN<<1],root,last,sz; inline void Init() {root=sz=last=1;} inline void Extend(int c) { int cur=++sz,p=last; len[cur]=len[p]+1; while (p && !son[p][c]) son[p][c]=cur,p=par[p]; if (!p) par[cur]=root; else { int q=son[p][c]; if (len[p]+1==len[q]) par[cur]=q; else { int nq=++sz; memcpy(son[nq],son[q],sizeof(son[nq])); len[nq]=len[p]+1; par[nq]=par[q]; while (p && son[p][c]==q) son[p][c]=nq,p=par[p]; par[cur]=par[q]=nq; } } last=cur; } inline void Build() {Init(); for (int i=1; i<=N; i++) Extend(A[i]-'a'+1);} inline int Query() { int now=root,Len=0,ans=0; for (int i=1; i<=M; i++) { int c=B[i]-'a'+1; if (son[now][c]) now=son[now][c],Len++; else { while (now && !son[now][c]) now=par[now]; if (!now) now=root,Len=0; else Len=len[now]+1,now=son[now][c]; } ans=max(ans,Len); } return ans; } }using namespace SAM; int main() { scanf("%s%s",A+1,B+1); N=strlen(A+1),M=strlen(B+1); SAM::Build(); printf("%d\n",SAM::Query()); return 0; }
SPOJ LCS2 - Longest Common Substring II
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define MAXN 250010 char A[MAXN],B[MAXN]; int N,M; namespace SAM { int son[MAXN<<1][27],len[MAXN<<1],par[MAXN<<1],mat[MAXN<<1],minn[MAXN<<1]; int sz,root,last; inline void Init() {last=root=sz=1;} inline void Extend(int c) { int cur=++sz,p=last; len[cur]=len[p]+1; while (p && !son[p][c]) son[p][c]=cur,p=par[p]; if (!p) par[cur]=root; else { int q=son[p][c]; if (len[p]+1==len[q]) par[cur]=q; else { int nq=++sz; memcpy(son[nq],son[q],sizeof(son[nq])); len[nq]=len[p]+1,par[nq]=par[q]; while (p && son[p][c]==q) son[p][c]=nq,p=par[p]; par[cur]=par[q]=nq; } } last=cur; } inline void Build() {Init(); for (int i=1; i<=N; i++) Extend(A[i]-'a'+1);} int st[MAXN],id[MAXN<<1]; inline void Pre() { for (int i=1; i<=sz; i++) st[len[i]]++; for (int i=1; i<=N; i++) st[i]+=st[i-1]; for (int i=1; i<=sz; i++) id[st[len[i]]--]=i; for (int i=1; i<=sz; i++) minn[i]=len[i]; } inline void Match() { for (int i=1; i<=sz; i++) mat[i]=0; int now=root,Len=0; for (int i=1; i<=M; i++) { int c=B[i]-'a'+1; if (son[now][c]) now=son[now][c],Len++; else { while (now && !son[now][c]) now=par[now]; if (!now) now=root,Len=0; else Len=len[now]+1,now=son[now][c]; } mat[now]=max(mat[now],Len); } } inline void Query() { for (int i=sz; i>=1; i--) { int now=id[i]; minn[now]=min(minn[now],mat[now]); if (par[now] && mat[now]) mat[par[now]]=len[par[now]]; } } } int ans=0; int main() { scanf("%s",A+1); N=strlen(A+1); SAM::Build(); SAM::Pre(); while (~scanf("%s",B+1)) M=strlen(B+1),SAM::Match(),SAM::Query(); for (int i=1; i<=SAM::sz; i++) ans=max(ans,SAM::minn[i]); printf("%d\n",ans); return 0; }
BZOJ SubString
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define MAXN 1200010 char S[MAXN]; int N,Q,M,ans,Mask; inline void read() { string str=S+1; int mask=Mask; for (int i=0; i<str.length(); i++) { mask=(mask*131+i)%str.length(); swap(str[i],str[mask]); } for (int i=0,tot=0; i<str.length(); i++) S[++tot]=str[i]; } namespace LCT { int fa[MAXN],ch[MAXN][2],val[MAXN],tag[MAXN]; inline bool is_root(int x) {return !fa[x] || ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;} inline void Add(int x,int v) {if (!x) return; val[x]+=v,tag[x]+=v;} inline void Pushdown(int x) {if (tag[x]) Add(ch[x][0],tag[x]),Add(ch[x][1],tag[x]),tag[x]=0;} inline void Rotate(int x) { int y=fa[x],w=ch[y][1]==x,z=fa[y]; ch[y][w]=ch[x][w^1]; if (ch[x][w^1]) fa[ch[x][w^1]]=y; if (ch[z][0]==y) ch[z][0]=x; else if (ch[z][1]==y) ch[z][1]=x; fa[x]=fa[y]; fa[y]=x; ch[x][w^1]=y; } int stack[MAXN]; inline void Splay(int x) { int top=0,t=x,y; stack[++top]=x; while (!is_root(t)) stack[++top]=t=fa[t]; while (top) Pushdown(stack[top--]); while (!is_root(x)) { y=fa[x]; if (!is_root(y)) if ((ch[fa[y]][0]==y)^(ch[y][0]==x)) Rotate(x); else Rotate(y); Rotate(x); } } inline void Access(int x) {for (int y=0; x; y=x,x=fa[x]) Splay(x),ch[x][1]=y;} inline void Link(int x,int y) {fa[x]=y; Access(y); Splay(y); Add(y,val[x]);} inline void Cut(int x) {Access(x); Splay(x); Add(ch[x][0],-val[x]); fa[ch[x][0]]=0,ch[x][0]=0;} }using namespace LCT; namespace SAM { int son[MAXN][27],len[MAXN],par[MAXN]; int root,last,sz; inline void Init() {root=last=sz=1;} inline void Extend(int c) { int cur=++sz,p=last; len[cur]=len[p]+1; LCT::val[cur]=1; while (p && !son[p][c]) son[p][c]=cur,p=par[p]; if (!p) par[cur]=root,LCT::Link(cur,root); else { int q=son[p][c]; if (len[p]+1==len[q]) par[cur]=q,LCT::Link(cur,q); else { int nq=++sz; memcpy(son[nq],son[q],sizeof(son[nq])); len[nq]=len[p]+1,par[nq]=par[q]; LCT::Link(nq,par[nq]); while (p && son[p][c]==q) son[p][c]=nq,p=par[p]; par[cur]=par[q]=nq; LCT::Cut(q); LCT::Link(cur,nq); LCT::Link(q,nq); } } last=cur; } inline void Build() {Init(); for (int i=1; i<=N; i++) Extend(S[i]-'A'+1);} inline void Insert() { read(); M=strlen(S+1); for (int i=1; i<=M; i++) Extend(S[i]-'A'+1); } inline int Query() { read(); M=strlen(S+1); int now=root; for (int i=1; i<=M; i++) if (!son[now][S[i]-'A'+1]) return 0; else now=son[now][S[i]-'A'+1]; LCT::Splay(now); return val[now]; } }using namespace SAM; int main() { scanf("%d",&Q); scanf("%s",S+1); N=strlen(S+1); SAM::Build(); while (Q--) { char opt[10]; scanf("%s%s",opt+1,S+1); switch (opt[1]) { case 'A' : SAM::Insert(); break; case 'Q' : printf("%d\n",ans=SAM::Query()); Mask^=ans; break; } // for (int i=1; i<=sz; i++) printf("%d %d %d %d\n",i,ch[i][0],ch[i][1],val[i]); } return 0; }
BZOJ 工艺
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 600010 int N,ans[MAXN],A[MAXN]; namespace SAM { int len[MAXN<<1],par[MAXN<<1],last,root,sz; map<int,int>son[MAXN<<1]; map<int,int>::iterator it; inline void Init() {last=root=sz=1;} inline void Extend(int c) { int cur=++sz,p=last; len[cur]=len[p]+1; while (p && !son[p][c]) son[p][c]=cur,p=par[p]; if (!p) par[cur]=root; else { int q=son[p][c]; if (len[p]+1==len[q]) par[cur]=q; else { int nq=++sz; son[nq]=son[q]; len[nq]=len[p]+1; par[nq]=par[q]; while (p && son[p][c]==q) son[p][c]=nq,p=par[p]; par[cur]=par[q]=nq; } } last=cur; } inline void Build() {Init(); for (int i=1; i<=N; i++) Extend(A[i]);} inline void Query() { int tot=0,now=root; while (tot!=(N>>1)) { it=son[now].begin(); now=it->second; ans[++tot]=it->first; } printf("%d",ans[1]); for (int i=2; i<=tot; i++) printf(" %d",ans[i]); puts(""); } }using namespace SAM; int main() { N=read(); for (int i=1; i<=N; i++) A[i+N]=A[i]=read(); N<<=1; SAM::Build(); SAM::Query(); return 0; }
——It's a lonely path. Don't make it any lonelier than it has to be.