[BZOJ2746][HEOI2012]旅行问题(AC自动机+LCA)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=2746

Solution

先介绍下 fail 树:
将 AC 自动机上每个点 u 的 fail 指针指向的点作为 u 的父亲,构成的树就是 fail 树。
应用:如果 fail 树上 u v 的祖先,那么 u 代表的字符串是 v 代表的字符串的前缀兼后缀。
而题意就是询问两个前缀的一个最长的公共后缀 S 满足 S 是给定串之一的前缀
结合 fail 树的性质和定义分析,可以发现此题可以转化为求 fail 树上两点的 LCA 。
套用 LCA 的模板即可通过此题。

Code

#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
inline int read() {
    int res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    return bo ? ~res + 1 : res;
}
const int N = 1e6 + 5, PYZ = 1e9 + 7, LogN = 22, E = 26;
int n, m, QAQ, len, que[N];
char s[N];
struct cyx {
    int son[E], dep, fa[LogN], code;
    void init() {
        dep = code = 0;
        memset(son, 0, sizeof(son));
        memset(fa, 0, sizeof(fa));
    }
} T[N];
vector<int> sp[N];
void ins(int id) {
    int i, u = 1, n = strlen(s + 1);
    For (i, 1, n) {
        int c = s[i] - 'a';
        if (!T[u].son[c]) T[T[u].son[c] = ++QAQ].init();
        T[T[u].son[c]].code = (26ll * T[u].code % PYZ + c) % PYZ;
        u = T[u].son[c]; sp[id].push_back(u);
    }
}
void cyxisdalao() {
    int i, c; T[0].init();
    For (c, 0, 25) T[0].son[c] = 1;
    que[len = 1] = 1; For (i, 1, len) {
        int u = que[i]; For (c, 0, 25)
            if (!T[u].son[c]) T[u].son[c] = T[T[u].fa[0]].son[c];
            else T[T[u].son[c]].fa[0] = T[T[u].fa[0]].son[c],
                T[T[u].son[c]].dep = T[T[T[u].son[c]].fa[0]].dep + 1,
                que[++len] = T[u].son[c];
        For (c, 0, 19) T[u].fa[c + 1] = T[T[u].fa[c]].fa[c];
    }
}
int lca(int u, int v) {
    int i; if (T[u].dep < T[v].dep) swap(u, v);
    Rof (i, 20, 0) {
        if (T[T[u].fa[i]].dep >= T[v].dep) u = T[u].fa[i];
        if (u == v) return u;
    }
    Rof (i, 20, 0) if (T[u].fa[i] != T[v].fa[i])
        u = T[u].fa[i], v = T[v].fa[i];
    return T[u].fa[0];
}
int main() {
    T[QAQ = 1].init(); T[1].dep = 1;
    int i, x, y, a, b; n = read();
    For (i, 1, n) scanf("%s", s + 1), ins(i);
    cyxisdalao(); m = read(); while (m--) {
        x = read(); y = read(); a = read(); b = read();
        printf("%d\n", T[lca(sp[x][y - 1], sp[a][b - 1])].code);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81167541
今日推荐