luogu SP8093 后缀自动机+树状数组+dfs序
这题解法很多,简单说几个:
1. 线段树合并,时间复杂度是 $O(nlog^2n)$ 的.
2. 暴力跳 $fail,$ 时间复杂度 $O(n\sqrt n),$ 比较暴力.
3. 建立后缀树后在 $dfs$ 序上数点,时间复杂度为 $O(nlogn),$ 十分优秀.
Code:
#include <bits/stdc++.h> #define N 200007 #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) using namespace std; struct ques { int l,r,id; ques(int l=0,int r=0,int id=0):l(l),r(r),id(id){} }q[N]; struct P { int len,f,ch[27]; vector<int>v; }t[N<<1]; char S[N]; vector<int>G[N]; int tot,last,edges,tim,cnt; int hd[N],to[N],nex[N],st[N],ed[N],size[N],dfn[N],lst[N],C[N],answer[N]; int lowbit(int t) { return t&(-t); } void update(int x,int delta) { for(;x<N;x+=lowbit(x)) C[x]+=delta; } int query(int x) { int tmp=0; for(;x>0;x-=lowbit(x)) tmp+=C[x]; return tmp; } bool cmp(ques a,ques b) { return a.r<b.r; } void addedge(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } void extend(int c,int id) { if(t[last].ch[c]) { int p=last; int q=t[p].ch[c]; if(t[q].len==t[p].len+1) last=q; else { int nq=++tot; t[nq].len=t[p].len+1; t[nq].f=t[q].f,t[q].f=nq; memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch)); for(;p&&t[p].ch[c]==q;p=t[p].f) t[p].ch[c]=nq; last=nq; } } else { int np=++tot,p=last; t[np].len=t[p].len+1,last=np; for(;p&&!t[p].ch[c];p=t[p].f) t[p].ch[c]=np; if(!p) t[np].f=1; else { int q=t[p].ch[c]; if(t[q].len==t[p].len+1) t[np].f=q; else { int nq=++tot; t[nq].len=t[p].len+1; t[nq].f=t[q].f,t[q].f=t[np].f=nq; memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch)); for(;p&&t[p].ch[c]==q;p=t[p].f) t[p].ch[c]=nq; } } } t[last].v.push_back(id); } void dfs(int u) { dfn[u]=st[u]=++tim; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; dfs(v); } for(int k=0;k<t[u].v.size();++k) G[dfn[u]].push_back(t[u].v[k]); ed[u]=tim; } int main() { last=tot=1; int i,j,n,m,k; // setIO("input"); scanf("%d%d",&n,&m); for(i=1;i<=n;++i) { last=1; scanf("%s",S+1); int len=strlen(S+1); for(j=1;j<=len;++j) extend(S[j]-'a',i); } for(i=2;i<=tot;++i) addedge(t[i].f,i); dfs(1); for(i=1;i<=m;++i) { scanf("%s",S+1); int len=strlen(S+1),p=1; for(j=1;j<=len;++j) { int c=S[j]-'a'; if(!t[p].ch[c]) { p=-1; break; } else p=t[p].ch[c]; } if(p!=-1) q[++cnt]=ques(st[p],ed[p],i); } sort(q+1,q+1+cnt,cmp); for(j=i=1;i<=cnt;++i) { for(;j<=q[i].r;++j) { for(k=0;k<G[j].size();++k) { int tt=G[j][k]; if(lst[tt]) update(lst[tt],-1); lst[tt]=j; update(j,1); } } answer[q[i].id]=query(q[i].r)-query(q[i].l-1); } for(i=1;i<=m;++i) printf("%d\n",answer[i]); return 0; }