Cod sursa(job #3307357)

Utilizator raileanu-alin-gabrielRaileanu Alin-Gabriel raileanu-alin-gabriel Data 20 august 2025 13:30:56
Problema Aho-Corasick Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.53 kb
#include <fstream>
#include <vector>
#include <queue>
#include <stack>

using namespace std;
ifstream cin("ahocorasick.in");
ofstream cout("ahocorasick.out");

/*
    Aho-Corasick

    Acest algoritm este practic o generalizare
    a algoritmului KMP (varianta cu automaton).

    In termeni tehnici, exista aceste suffixLinks 
    (atunci cand desenam se vad ca niste arce in sus din trie)
    care reprezinta pentru fiecare nod exact finalul
    celui mai lung sufix prefix din algoritmul KMP,
    dar considerand toate nodurile din trie, nu doar
    cele de pe path ul de la root la nod.

    Pentru a gasi aceste suffixLinks sunt 2 variante:
    1. recursivitate indirecta
    2. bfs

    Acest cod foloseste varianta 2.
    (am trimis in trecut un cod si cu prima varianta,
    dar implementat mult mai urat :))
*/

class Node {
public:
    Node** kids;   
    Node* suffixLink;
    int cnt;

    Node(int alphaSize) {
        kids = new Node*[alphaSize];
        for (int i = 0; i < alphaSize; i++) {
            kids[i] = NULL;
        }
        suffixLink = NULL;
        cnt = 0;
    }
};

class AhoCorasick {
public:

    Node* root;
    int alphaSize;

    AhoCorasick(int size) {
        alphaSize = size;
        root = new Node(size);
    }

    bool checkChild(Node* node, int childId) {
        return (node->kids[childId] != NULL);
    }

    void addChild(Node* node, int childId) {
        node->kids[childId] = new Node(alphaSize);
    }

    Node* insert(string s) {
        Node* node = root;

        for (char ch: s) {
            int childId = int(ch - 'a');
            if (!checkChild(node, childId)) {
                addChild(node, childId);
            }

            node = node->kids[childId];
        }

        return node;
    }

    void solvePrefix(Node* node, int childId) {
        Node* pref = node->suffixLink;

        while (pref != root && !checkChild(pref, childId)) {
            pref = pref->suffixLink;
        }

        if (checkChild(pref, childId) && pref->kids[childId] != node->kids[childId]) {
            node->kids[childId]->suffixLink = pref->kids[childId];
        } else {
            node->kids[childId]->suffixLink = root;
        }
    }

    void buildAndSolve(string s) {
        root->suffixLink = root;

        vector<Node*> q;
        q.push_back(root);

        for (int j = 0; j < int(q.size()); j++) {
            Node* node = q[j];

            for (int i = 0; i < alphaSize; i++) {
                if (checkChild(node, i)) {
                    solvePrefix(node, i);
                    q.push_back(node->kids[i]);
                }
            }
        }

        Node* node = root;

        for (char ch: s) {
            int childId = int(ch - 'a');

            while (node != root && !checkChild(node, childId)) {
                node = node->suffixLink;
            }

            if (checkChild(node, childId)) {
                node = node->kids[childId];
            }

            node->cnt++;
        }

        for (int i = q.size() - 1; i >= 0; i--) {
            Node* node = q[i];
            node->suffixLink->cnt += node->cnt;
        }
    }

    void solve(string s) {
        Node* node = root;

        for (char ch: s) {
            int childId = int(ch - 'a');

            while (node != root && !checkChild(node, childId)) {
                node = node->suffixLink;
            }

            if (checkChild(node, childId)) {
                node = node->kids[childId];
            }

            node->cnt++;
        }

        vector<Node*> bfsOrder;
        bfsOrder.push_back(root);

        for (int i = 0; i < int(bfsOrder.size()); i++) {
            Node* node = bfsOrder[i];

            for (int j = 0; j < alphaSize; j++) {
                if (checkChild(node, j)) {
                    bfsOrder.push_back(node->kids[j]);
                }
            }
        }

        for (int i = bfsOrder.size() - 1; i >= 0; i--) {
            Node* node = bfsOrder[i];
            node->suffixLink->cnt += node->cnt;
        }
    }
};

int main() {
    int n;
    string text;
    cin >> text >> n;

    AhoCorasick automaton(26);

    Node* termNodes[n];
    for (int i = 0; i < n; i++) {
        string pattern;
        cin >> pattern;

        termNodes[i] = automaton.insert(pattern);
    }

    automaton.buildAndSolve(text);
    // automaton.solve(text);

    for (int i = 0; i < n; i++) {
        cout << termNodes[i]->cnt << '\n';
    }
}