嘘~ 正在从服务器偷取页面 . . .

洛谷P5829 【模板】失配树 题解


洛谷P5829 【模板】失配树 题解

题目链接:P5829 【模板】失配树

题意

给定一个字符串 \(s\),定义它的 \(k\) 前缀 \(\mathsf{pre}_k\) 为字符串 \(s_{1\dots k}\)\(k\) 后缀 \(\mathsf{suf}_k\) 为字符串 \(s_{|s|-k+1\dots |s|}\),其中 \(1 \le k \le |s|\)

定义 \(\mathrm{Border}(s)\)对于 \(i \in [1, |s|)\),满足 \(\mathsf{pre}_i = \mathsf{suf}_i\) 的字符串 \(\mathsf{pre}_i\) 的集合。\(\mathrm{Border}(s)\) 中的每个元素都称之为字符串 \(s\)\(\operatorname{border}\)

\(m\) 组询问,每组询问给定 \(p,q\),求 \(s\)\(\boldsymbol{p}\) 前缀\(\boldsymbol{q}\) 前缀最长公共 \(\operatorname{border}\) 的长度。

输入格式

第一行一个字符串 \(s\)

第二行一个整数 \(m\)

接下来 \(m\) 行,每行两个整数 \(p,q\)

输出格式

对于每组询问,一行一个整数,表示答案。若不存在公共 \(\operatorname{border}\),请输出 \(0\)

数据范围

\(1\leq p,q \le |s|\leq 10^6\)\(1 \leq m \leq 10^5\)\(s_i \in [\texttt{a}, \texttt{z}]\)

就硬搞个模板题呗,不如直接去做 AC 自动机板子

显然就是跑一遍 kmp ,然后在 fail 树上面搞。

注意到前缀 \(p,q\) 的最长公共 border其实就是 \(p\)\(q\) 在树上的 LCA

不过有个特例, \(p,q\) 中有一个为 LCA 时,答案就是 LCA 的父亲,因为 border 不能和原长相等。

其实实现的时候只需要查一下 \(\,\mathsf{fa}(p),\mathsf{fa}(q)\) 的 LCA 就好了

时间复杂度 \(\mathcal{O}(n \log n)\)

代码:

#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define fail(x) (fa[x][0])
#define N ((int)(1e6 + 15))

char s[N];
int n,dep[N],lg[N],fa[N][22];
int lca(int x,int y)
{
    if(dep[x] < dep[y]) swap(x,y);
    while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
    if(x == y) return x;
    for(int i=lg[dep[x]]; ~i; i--)
        if(fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; }
    return fa[x][0];
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);

    cin >> (s + 1); n = strlen(s + 1);
    lg[1] = 0 + 1; fa[1][0] = 0; dep[0] = 1; dep[1] = 2;
    for(int i=2; i<=n; i++) lg[i] = lg[i >> 1] + 1;
    for(int i=2, j=0; i<=n; i++)
    {
        while(j != 0 && s[i] != s[j + 1]) j = fail(j);
        if(s[i] == s[j + 1]) ++j; fail(i) = j; dep[i] = dep[j] + 1;
    }
    for(int i=1; i<=n; i++)
        for(int k=1; k<=lg[dep[i]]; k++) fa[i][k] = fa[fa[i][k - 1]][k - 1];
    int Q; cin >> Q; for(int p,q; Q--; )
    {
        cin >> p >> q;
        cout << lca(fa[p][0],fa[q][0]) << '\n';
    }
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录