P6257 [ICPC 2019 WF] First of Her Name 题解

前言

  • 能推的题 \(+1\)

\(solve\)

  • 我们发现名字是向前接的,不好搞,我们让它向后接,即从第一代王后为开始向下建立 \(Trie\),好理解,不过还是画张图,模个样例

2026-10-05 19-42-10屏幕截图

  • 那我们要做的就是从任意一个节点开始到根的串,询问串是其前缀的个数
  • 那么你就有一个 \(O(n^3)\) 的做法了
  • 我们发现我们建这棵 \(Trie\) 是倒着建的,而我们要查前缀还要倒着遍历 \(Trie\),非常不美丽,那我们为啥不让询问串也反过来,这样就成询问从 \(Trie\) 根出发到任意节点形成的串的后缀了
  • 给你文本串和模式串​,分别求出每个模式串对于每个文本串中出现的次数,这你想到了啥,\(AC\) 自动机板子
  • 你直接在 \(Trie\) 的节点上暴力匹配,每到一个节点,在 \(ACAM\) 上转移到其对应的节点,增加计数器,最后像板子一样直接跑 \(fail\) 树的 \(topo\) 就行了
点击查看代码
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
constexpr int maxn=1e6+10;
int n,m;
char s[maxn];
vector<int> e[maxn];
namespace ACAM
{
    struct _ {int ch[26],fail,d,id;}t[maxn];
    int tot,pid;
    void BuildTrie(string s,int &id)
    {
        int x=0;
        for (int i=0;i<s.size();i++)
        {
            int &son=t[x].ch[s[i]-'A'];
            if (!son) son=++tot;
            x=son;
        }
        if (!t[x].id) t[x].id=++pid;
        id=t[x].id;
    }
    void BuildACAM()
    {
        queue<int> q;
        for (int i=0;i<26;i++)
            if (t[0].ch[i])
                q.push(t[0].ch[i]);
        while (!q.empty())
        {
            int x=q.front();q.pop();
            for (int i=0;i<26;i++)
            {
                if (t[x].ch[i])
                    t[t[x].ch[i]].fail=t[t[x].fail].ch[i],
                    t[t[t[x].fail].ch[i]].d++,q.push(t[x].ch[i]);
                else
                    t[x].ch[i]=t[t[x].fail].ch[i];
            }
        }
    }
}using namespace ACAM;
int idx[maxn];
int cnt[maxn];
void dfs(int x,int fa,int p)
{
    p=t[p].ch[s[x]-'A'];
    cnt[p]++;
    for (int y:e[x])
        if (y!=fa)
            dfs(y,x,p);
}
int ans[maxn];
void topo()
{
    queue<int> q;
    for (int i=0;i<=tot;i++)
        if (!t[i].d)
            q.push(i);
    while (!q.empty())
    {
        int x=q.front();q.pop();
        ans[t[x].id]=cnt[x];
        int y=t[x].fail;
        cnt[y]+=cnt[x];
        if (!(--t[y].d))
            q.push(y);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin >> n >> m;
    for (int i=1;i<=n;i++)
    {
        cin >> s[i];
        int x;cin >> x;
        e[x].pb(i),e[i].pb(x);
    }
    for (int i=1;i<=m;i++)
    {
        string k;
        cin >> k;
        reverse(k.begin(),k.end());
        BuildTrie(k,idx[i]);
    }
    BuildACAM();
    dfs(1,0,0);
    topo();
    for (int i=1;i<=m;i++)
        cout << ans[idx[i]] << endl;
    return 0;
}
posted @ 2026-10-05 19:53  msjing  阅读(7)  评论(0)    收藏  举报