[洛谷P5829] 失配树
作者:互联网
题目大意
给定一长为 \(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;
}
标签:ch,洛谷,Anc,RG,KMP,fail,P5829,include,失配 来源: https://www.cnblogs.com/AEMShana/p/13709174.html