Cod sursa(job #1556346)

Utilizator andreiiiiPopa Andrei andreiiii Data 24 decembrie 2015 17:18:02
Problema Aho-Corasick Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.1 kb
#include <algorithm>
#include <fstream>
#include <cstring>
#define SZ(x) ((int) (x).size())
using namespace std;

const int NMAX = 1000005, MMAX = 10005;

char A[NMAX];
char word[MMAX];

int answers[105];

struct Node {
    int cnt;
    vector<int> words;
    Node *links[26], *fail;

    Node():
        cnt(0), words(vector<int>()), links{0}, fail(0) {}
};

void addWord(Node *node, char *s, int ind) {
    if (*s == '\n' || *s == '\0') {
        node->words.push_back(ind);
    } else {
        int p = *s - 'a';
        if (node->links[p] == NULL) {
            node->links[p] = new Node();
        }
        addWord(node->links[p], s + 1, ind);
    }
}

vector<Node*> q;

void buildFail(Node *root) {
    root->fail = root;
    q.push_back(root);
    int l = 0, r = 1;
    while (l < r) {
        Node* node = q[l++];
        for (int i = 0; i < 26; ++i) {
            if (node->links[i] != NULL) {
                Node *k;
                for (k = node->fail; k != root && !k->links[i]; k = k->fail);
                if (k->links[i] && k->links[i] != node->links[i])
                    k = k->links[i];
                node->links[i]->fail = k;
                q.push_back(node->links[i]);
                r++;
            }
        }
    }

    root->fail = NULL;
}

void countAll() {
    for (int i = SZ(q) - 1; i >= 0; --i) {
        Node *node = q[i];
        if (node->fail) node->fail->cnt += node->cnt;
        for (int p: node->words) answers[p] = node->cnt;
    }
}

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

    fin >> A + 1;
    int n = strlen(A + 1);

    int m;
    fin >> m;

    Node *root = new Node();
    for (int i = 1; i <= m; ++i) {
        fin >> word;
        addWord(root, word, i);
    }

    buildFail(root);

    Node *curr = root;
    for (int i = 1; i <= n; ++i) {
        int p = A[i] - 'a';
        while (curr->links[p] == NULL && curr != root) curr = curr->fail;
        if (curr->links[p]) curr = curr->links[p];
        curr->cnt++;
    }

    countAll();

    for (int i = 1; i <= m; ++i)
        fout << answers[i] << '\n';

    fin.close();
    fout.close();
}