失配树

又叫做 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;
}
posted @ 2023-08-12 22:57  Hypoxia571  阅读(16)  评论(0编辑  收藏  举报