[洛谷P5829] 失配樹
阿新 • • 發佈:2020-09-22
題目大意
給定一長為 \(n(n\leq 10^6)\) 的字串 \(s\),\(m(m\leq 5\times 10^5)\)次詢問,每次詢問它的兩個字首的最長公共 border。
題解
先跑一遍KMP求出\(fail\)陣列,每個\(pos\)向\(fail[pos]\)連邊,建出\(fail\)樹,在\(fail\)樹上求lca即為兩個字首的最長公共border。
Code
#include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cstdio> #include <vector> using namespace std; #define RG register int #define LL long long template<typename elemType> inline void Read(elemType &T){ elemType X=0,w=0; char ch=0; while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); T=(w?-X:X); } const int maxn=1000010; struct Graph{ struct edge{int Next,to;}; edge G[maxn<<1]; int head[maxn]; int cnt; Graph():cnt(2){} void clear(int node_num=0){ cnt=2; if(node_num==0) memset(head,0,sizeof(head)); else fill(head,head+node_num+5,0); } void add_edge(int u,int v){ G[cnt].to=v; G[cnt].Next=head[u]; head[u]=cnt++; } }; namespace KMP{ int LenP=0,*Fail=NULL; char *P=NULL; inline void bind_kmp(char *_P,int *_Fail,int _len){ P=_P;Fail=_Fail; LenP=_len; } inline void get_fail(){//求出Fail陣列 Fail[1]=0; for(RG i=2,pos=0;i<=LenP;++i){ while(pos && (pos==LenP || P[i]!=P[pos+1])) pos=Fail[pos]; if(P[i]==P[pos+1]) ++pos; Fail[i]=pos; } } }; Graph G; char s[maxn]; int Fail[maxn]; int N,M; int Deep[1000010],Anc[1000010][20]; void DFS_Init(int u,int fa){ Anc[u][0]=fa; for(int i=1;i<20;++i) Anc[u][i]=Anc[Anc[u][i-1]][i-1]; for(int i=G.head[u];i;i=G.G[i].Next){ int v=G.G[i].to; if(v==fa) continue; Deep[v]=Deep[u]+1; DFS_Init(v,u); } return; } int LCA(int u,int v){ int Root=N+1; if(u==Root || v==Root) return Root; if(Deep[u]<Deep[v]) swap(u,v); for(RG i=19;i>=0;--i){ if(Deep[Anc[u][i]]>=Deep[v]) u=Anc[u][i]; } if(u==v) return u; for(RG i=19;i>=0;--i){ if(Anc[u][i]!=Anc[v][i]){ u=Anc[u][i]; v=Anc[v][i]; } } return Anc[u][0]; } int main(){ scanf("%s",s+1); N=strlen(s+1); KMP::bind_kmp(s,Fail,N); KMP::get_fail(); for(RG u=1;u<=N;++u){ int v=Fail[u]; if(v==0) v=N+1; G.add_edge(u,v); G.add_edge(v,u); } DFS_Init(N+1,0); Read(M); while(M--){ int u,v; Read(u);Read(v); u=Fail[u];v=Fail[v]; if(!u || !v) printf("0\n"); else{ int Ans=LCA(u,v); if(Ans==N+1) Ans=0; printf("%d\n",Ans); } } return 0; }