Cod sursa(job #2724552)

Utilizator iancupoppPopp Iancu Alexandru iancupopp Data 17 martie 2021 12:19:14
Problema Aho-Corasick Scor 95
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.41 kb
#include <fstream>
#include <queue>

using namespace std;

class Node {
public:
    Node* children[26];
    Node* suffix;
    Node* output;
    Node* parent;
    bool is_pattern;
    char ch;
    int occ;
    Node() : children(), suffix(), output(), parent(), is_pattern(), ch(), occ() {}
};

class Trie {
public:
    Node* root;
    Trie() : root(new Node) {}

    void insert(string s) {
        Node* crt = root;
        for (auto ch : s) {
            if (!crt->children[ch - 'a'])
                crt->children[ch - 'a'] = new Node;
            crt->children[ch - 'a']->parent = crt;
            crt->children[ch - 'a']->ch = ch;
            crt = crt->children[ch - 'a'];
        }
        crt->is_pattern = true;
    }

    void build_suffix_links() {
        queue<Node*> q;
        for (int i = 0; i < 26; ++i)
            if (root->children[i]) {
                root->children[i]->suffix = root;
                q.push(root->children[i]);
            }
        while (!q.empty()) {
            Node* crt = q.front();
            q.pop();
            for (int i = 0; i < 26; ++i)
                if (crt->children[i])
                    q.push(crt->children[i]);
            Node* s = crt->parent->suffix;
            while (s && !s->children[crt->ch - 'a'])
                s = s->suffix;
            if (s)
                crt->suffix = s->children[crt->ch - 'a'];
            else
                crt->suffix = root;
        }
    }

    void build_output_links() {
        queue<Node*> q;
        for (int i = 0; i < 26; ++i)
            if (root->children[i])
                q.push(root->children[i]);
        while (!q.empty()) {
            Node* crt = q.front();
            q.pop();
            for (int i = 0; i < 26; ++i)
                if (crt->children[i])
                    q.push(crt->children[i]);
            Node* s = crt->suffix;
            if (s->is_pattern)
                crt->output = s;
            else
                crt->output = s->output;
        }
    }

    void build() {
        build_suffix_links();
        build_output_links();
    }

    void run(string s) {
        Node* crt = root;
        for (auto ch : s) {
            if (crt->children[ch - 'a'])
                crt = crt->children[ch - 'a'];
            else {
                while (crt != root) {
                    crt = crt->suffix;
                    if (crt->children[ch - 'a']) {
                        crt = crt->children[ch - 'a'];
                        break;
                    }
                }
            }
            Node* o;
            if (crt->is_pattern)
                o = crt;
            else
                o = crt->output;
            while (o) {
                ++o->occ;
                o = o->output;
            }
        }
    }

    int count_occ(string s) {
        Node* crt = root;
        for (auto ch : s)
            crt = crt->children[ch - 'a'];
        return crt->occ;
    }
};

const int N = 100;

string txt, pat[N];
Trie t;

int main() {
    ifstream in("ahocorasick.in");
    ofstream out("ahocorasick.out");

    int n;
    in >> txt >> n;
    for (int i = 0; i < n; ++i) {
        in >> pat[i];
        t.insert(pat[i]);
    }
    t.build();
    t.run(txt);
    for (int i = 0; i < n; ++i)
        out << t.count_occ(pat[i]) << '\n';

    in.close();
    out.close();
    return 0;
}