P5829 【模板】失配树
求公共 \(border\),,,求 \(border\) 我会,\(KMP\)。那么我直接做 M 次 KMP。
显然会TLE,但是我们也可以用 \(KMP\) 先求一下原串的 \(border\)。
然后我们可以发现,\(border\) 的 \(border\) 也是 \(border\) 那么我们可以利用这个关系建一棵树,然后我们可以发现,对于这样一棵树,最近公共祖先就是公共 \(border\) 的长度。那么我们倍增跳就行了。
(注意:当 \(p, q\) 是 \(lca\) 的时候,要再向上跳一层,因为 \(border\) 要求左闭右开)
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6+10;
ll N, M, fa[MAXN][22], dep[MAXN];
char ss[MAXN];
void gtn();
ll lca(ll, ll); 
int main() {
    ios::sync_with_stdio(false);
    cin >> (ss+1);
    gtn();
    cin >> M;
    for (ll i = 1, p, q; i <= M; i++) {
        cin >> p >> q;
        ll lc = lca(p, q);
        if (lc == p || lc == q) lc = fa[lc][0];
        printf("%lld\n", lc);
    }
    return 0;
}
ll lca(ll x, ll y) {
    if (dep[x] < dep[y]) swap(x, y);
    ll dis = dep[x] - dep[y];
    for (ll i = 20; ~i; i--) {
        if ((dis >> i) & 1) {
            x = fa[x][i];
        }
    }
    if (x == y) return x;
    for (ll i = 20; ~i; i--) {
        if (fa[x][i] != fa[y][i]) {
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    return fa[x][0];
}
void gtn() {
    ll len = strlen(ss+1);
    for (ll i = 2, j = 0; i <= len; i++) {
        while (j != 0 && ss[j+1] != ss[i]) j = fa[j][0];
        if (ss[j+1] == ss[i]) j++;
        fa[i][0] = j, dep[i] = dep[j]+1;
    }
    for (ll i = 1; i <= 20; i++) {
        for (ll j = 1; j <= len; j++) {
            fa[j][i] = fa[fa[j][i-1]][i-1];
        }
    }
}
    希望我们都有一个光明的未来
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号