失配树
失配树
题意简述
求 \(s\) 的 \(p\) 前缀 和 \(q\) 前缀 的 最长公共 \(border\) 的长度。
解法
- 用 \(kmp\) 求 \(s\) 的 \(nxt\) 数组, 则S 的所有 \(border\) 为 \(s_{1..nxt(|s|)},s_{1..nxt(nxt(|s|)),...,s_{1..nxt(..nxt(|s|))}\)
- 通过 \(nxt\) 数组建一棵树(\(fail\) 树)
- 在 \(fail\) 树上求 \(LCA\)
code
求nxt数组+建树
il void getfail(){
len=strlen(s+1);
for(int i=2,j=0;i<=len;i++){
while(j&&s[i]!=s[j+1]) j=f[j][0];
if(s[i]==s[j+1]) j++;
f[i][0]=j,dep[i]=dep[j]+1;
for(ri int k=1;k<=21;++k){
f[i][k]=f[f[i][k-1]][k-1];
}
}
return;
}
code
#include <bits/stdc++.h>
#define il inline
#define cs const
#define ri register
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10|48),void();
}
} using namespace Q;
cs int N=1e6+5;
char s[N];
int m,p,q,f[N][22],len,dep[N];
il void getfail(){
len=strlen(s+1);
for(int i=2,j=0;i<=len;i++){
while(j&&s[i]!=s[j+1]) j=f[j][0];
if(s[i]==s[j+1]) j++;
f[i][0]=j,dep[i]=dep[j]+1;
for(ri int k=1;k<=21;++k){
f[i][k]=f[f[i][k-1]][k-1];
}
}
return;
}
il int lca(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
for(ri int i=21;~i;--i){
if(dep[f[a][i]]>=dep[b]) a=f[a][i];
}
for(ri int i=21;~i;--i){
if(f[a][i]^f[b][i]) a=f[a][i],b=f[b][i];
}
return f[a][0];
}
signed main(){
scanf("%s",s+1);//
getfail(),m=rd();
for(ri int i=1;i<=m;++i){
p=rd(),q=rd();
wt(lca(p,q)),putchar(10);
}
return 0;
}
I went to the woods because I wanted to live deliberately, I wanted to live deep and suck out all the marrow of life, and not when I had come to die, discover that I had not live.