失配树
又叫做 fail 樹。可愛捏(((
用於求解字符串兩個前綴的最大公共 border。
我們先跑一邊 KMP 算法求出 \(nxt[]\) 數組。
我們連出每一個邊 \((nxt[i],i)\),嗯嗯為此我們需要新建一個 \(0\) 點。
那這個樹有什麼性質捏,顯然一個節點的祖先都是祂的 border。
額大家都知道 border 的 border 還是 border 啦(
查公共前缀其实就是父亲的 lca。
感覺用了這個字說話好機車的說。
#include<bits/stdc++.h>
#define MN 2010000
using namespace std;
char s[MN];
int n, m, f[MN][22];
int t, nxt[MN], dep[MN];
int lca(int u,int v) {
if(dep[u]<dep[v]) swap(u,v);
for(int i=t; i>=0; --i)
if(dep[f[u][i]]>=dep[v]) u=f[u][i];
if(u==v) return u;
for(int i=t; i>=0; --i)
if(f[u][i]^f[v][i])
u=f[u][i], v=f[v][i];
return f[u][0];
}
signed main() {
cin >> (s+1) >> m;
n=strlen(s+1), t=log2(n)+1;
dep[0]=1, dep[1]=2, f[1][0]=0;
for(int i=2, j=0; i<=n; ++i) {
while(j&&s[j+1]!=s[i]) j=nxt[j];
j+=(s[j+1]==s[i]), nxt[i]=j;
f[i][0]=j, dep[i]=dep[j]+1;
for(int k=1; k<t; ++k)
f[i][k]=f[f[i][k-1]][k-1];
}
while(m--) {
int u, v;
cin >> u >> v;
u=f[u][0], v=f[v][0];
cout << lca(u,v) << endl;
}
return 0;
}