P5829 【模板】失配树

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];
        }
    }
}
posted @ 2020-09-23 16:35  Gensokyo_Alice  阅读(114)  评论(0)    收藏  举报