有没有佬教教哪里错了
查看原帖
有没有佬教教哪里错了
1159937
520689892yhw楼主2024/9/14 22:10
#include<iostream>
#include<vector>
#include<array>
#include<string>
#include<queue>

using ll = long long;
using i64 = long long;

struct AhoCorasick {
    static constexpr int ALPHABET = 26;
    struct Node {
        int len;//有什么用
        int link;
        std::array<int, ALPHABET> next;
        int end = -1;
        Node() : len{ 0 }, link{ 0 }, next{} {}//长度和fail指针都指向0
    };

    std::vector<Node> t;//节点都存在t里面,

    AhoCorasick() {
        init();
    }

    void init() {
        t.assign(2, Node());
        t[0].next.fill(1);//每一个都通向根节点
        t[0].len = -1;//长度赋为-1
    }

    int newNode() {
        t.emplace_back();//t末尾新增一个节点
        return t.size() - 1;//返回它在哪个位置
    }

    int add(const std::string& a,int pos) {
        int p = 1;//t[1]表示根节点?
        for (auto c : a) {//每一个字符,从根节点开始
            int x = c - 'a';
            //t[p]表示该节点,next[x]表示该点节点的子节点中字符为x的节点在t的哪个位置,
            if (t[p].next[x] == 0) {
                t[p].next[x] = newNode();//t[p].next[x]表示要构建的新节点
                t[t[p].next[x]].len = t[p].len + 1;//父节点的长度+1
            }
            p = t[p].next[x];
        }
        t[p].end = pos;
        return p;//add返回的是一个a最后一个字符所在的节点位置
    }

    void work() {
        //队列
        std::queue<int> q;
        q.push(1);//放入根节点

        while (!q.empty()) {
            int x = q.front();
            q.pop();//每次取一个点
            //遍历子节点
            //t[x]父节点,t[x].next[i]子节点,t[x].link子节点的fail指针指向对应的最长后缀
            for (int i = 0; i < ALPHABET; i++) {
                if (t[x].next[i] == 0) {//子节点为空?//就是让它指向子节点
                    t[x].next[i] = t[t[x].link].next[i];//根节点的link指向0,t[0]的子节点都为根节点,所以是将空节点赋为根节点
                }
                else {//指向付姐带你的fail指针指向的节点下的子节点
                    t[t[x].next[i]].link = t[t[x].link].next[i];//将该子节点的link指向父节点fail指针指向的节点的子节点
                    q.push(t[x].next[i]);
                }
            }
        }
    }
    
    int next(int p, int x) {
        return t[p].next[x];
    }

    int link(int p) {
        return t[p].link;
    }

    int len(int p) {
        return t[p].len;
    }

    int size() {
        return t.size();
    }
};

int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    int n;
    AhoCorasick ac;
    std::cin >> n;

    std::vector<std::string> v(n);
    std::vector<int>ans(n);
    // sum 用于记录节点上模式串的匹配情况

    // 添加所有模式串到AC自动机
    for (int i = 0; i < n; i++) {
        std::cin >> v[i];
        ac.add(v[i],i);
    }
    // 对于每个模式串的终止节点,累加匹配的次数
    // 构建AC自动机
    ac.work();
    std::string s;
    std::cin >> s;
    int p = 1;
    for (int i = 0; i < s.size(); i++) {
        p = ac.next(p, s[i] - 'a');
        // 当前节点可能对应多个模式串,沿着fail指针回溯
        for (int temp = p; temp != 0; temp = ac.link(temp)) {
            if (ac.t[temp].end != -1) {
                ans[ac.t[temp].end]++;
            }
        }
    }
    for (int i = 0; i < n; i++)std::cout << ans[i] << "\n";
    return 0;
}
2024/9/14 22:10
加载中...