失配树模板题 题解
给定一个字符串 \(s\),定义它的 \(k\) 前缀 \(pre_k\) 为字符串 \(s_{1\dots k}\),\(k\) 后缀 \(suf_k\) 为字符串 \(s_{|s|-k+1\dots |s|}\),其中 \(1\le k\le |s|\)。
定义 \(Border(s)\) 为对于 \(1\leq i\lt |s|\),满足 \(pre_i=suf_i\) 的字符串 \(pre_i\) 的集合。\(Border(s)\) 中的每个元素都称之为字符串 \(s\) 的 \(border\)。
有 \(m\) 组询问,每组询问给定 \(p,q\),求 \(s\) 的 \(p\) 前缀和 \(q\) 前缀的最长公共 \(border\) 的长度。
题目跳转
一看数据范围,这道题用简单普通的哈希或 \(KMP\) 肯定是写不了的,所以引入失配树。
我们先来看一组样例:
假设这是我们找出的一个字符串的两个前缀。我们可以发现它们的最长公共 \(border\) 长度是 \(3\)。
说到求 \(border\),就需要用 \(KMP\) 了,既然两个字符串都是同一个串的前缀,那么其中一个(较短的)必定也是另一个(较长的)字符串的前缀,然后我们将其中较长的一个字符串的字符下标及其 \(nxt\) 数组列出来看看。
显然什么也看不出来,那把它建成一棵树:我们连边 \((nxt[i],i),i\in[1,6]\)。
长度为 \(4\) 和长度为 \(6\) 的后缀的最长公共 \(border\) 长为 \(2\),在树上的关系是 \(2\) 是 \(4\) 和 \(6\) 除了自己之外的 \(LCA\)。
原理:
如果 \(C\) 是 \(B\) 的 \(border\),\(B\) 是 \(A\) 的 \(border\),那么 \(C\) 是 \(A\) 的 \(border\). 也就是说处理出 \(nxt\) 数组之后,\(A\) 可以不断跳 \(nxt\) 到 \(B\),\(B\) 也可以不断跳 \(nxt\) 到 \(C\)。所以说,如果两个前缀能通过跳 \(nxt\) 跳到同一个位置去,那么第一个跳到的相同的位置就是它们的最长公共 \(border\) 长度。这个过程和我们树上找 \(LCA\) 的方式很像,所以我们可以将其建成一棵树,这棵树也就是所谓的失配树。
通过对于一个字符串建出的失配树,我们可以快速找出其多组长度不同的前缀的最长公共 \(border\) 长度。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e6+5;
ll n,m,p,q,nxt[maxn],dep[maxn],f[maxn][21];
char s[maxn];
vector<ll> e[maxn];
void dfs(ll x,ll fa){
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(ll i=1;i<=20;i++){
f[x][i]=f[f[x][i-1]][i-1];
}
for(auto y:e[x]){
dfs(y,x);
}
}
ll lca(ll u,ll v){
if(dep[u]<dep[v]){
swap(u,v);
}
for(ll i=20;i>=0;i--){
if(dep[f[u][i]]>=dep[v]){
u=f[u][i];
}
}
// if(u==v){
// return u;
// }
// 因为要查除了u、v自己之外的LCA,所以上面三行不能要
for(ll i=20;i>=0;i--){
if(f[u][i]!=f[v][i]){
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>(s+1)>>m;
n=strlen(s+1);
for(ll i=2,j=0;i<=n;i++){
while(j&&s[i]!=s[j+1]){
j=nxt[j];
}
if(s[i]==s[j+1]){
j++;
}
nxt[i]=j;
}
for(ll i=1;i<=n;i++){
e[nxt[i]+1].push_back(i+1);//为了方便,建树时所有节点编号+1,这样就没有0号节点了
}
dfs(1,0);//dfs时从1号节点开始
while(m--){
cin>>p>>q;
cout<<lca(p+1,q+1)-1<<"\n";//因为建树是每个节点都+1,所以查询p+1、q+1,查完后再-1
}
return 0;
}

浙公网安备 33010602011771号