Pagini recente » Borderou de evaluare (job #2209969) | Cod sursa (job #309395) | preONI 2008 - Clasament general, Clasa a 10-a | Borderou de evaluare (job #2018306) | Cod sursa (job #3242423)
#include <fstream>
#include <string>
#include <vector>
#include <queue>
#include <functional>
const int SIGMA = 26;
struct Node
{
int cnt, mismatch;
std::vector<int> out;
Node()
{
cnt = 0, mismatch = -1;
out = std::vector<int>(SIGMA, -1);
}
};
class Aho
{
private:
std::vector<Node> nodes;
std::vector<int> word_ptr;
public:
Aho()
{
nodes.push_back({}); // root node
}
void insert(const std::string &word)
{
int idx = 0;
for (char c : word)
{
if (nodes[idx].out[c - 'a'] != -1)
idx = nodes[idx].out[c - 'a'];
else
{
nodes.push_back({});
int new_idx = (int)nodes.size() - 1;
nodes[idx].out[c - 'a'] = new_idx;
idx = new_idx;
}
}
word_ptr.push_back(idx);
}
bool can_extend(int node, int chr)
{
if (nodes[node].out[chr] == -1)
return false;
return true;
}
bool mismatch_can_extend(int node, int chr)
{
if (nodes[nodes[node].mismatch].out[chr] == -1)
return false;
return true;
}
void build()
{
std::function<void(int, int, int)> build_rec = [&](int node, int chr, int parent)
{
int candidate = nodes[parent].mismatch;
while (candidate > 0 && !can_extend(candidate, chr))
candidate = nodes[candidate].mismatch;
if (candidate != parent && can_extend(candidate, chr))
candidate = nodes[candidate].out[chr];
nodes[node].mismatch = candidate;
for (int i = 0; i < SIGMA; i++)
{
if (nodes[node].out[i] == -1)
continue;
build_rec(nodes[node].out[i], i, node);
}
};
nodes[0].mismatch = 0;
for (int i = 0; i < SIGMA; i++)
{
if (nodes[0].out[i] == -1)
continue;
build_rec(nodes[0].out[i], i, 0);
}
}
void walk(const std::string &text)
{
int idx = 0;
for (char c : text)
{
if (nodes[idx].out[c - 'a'] != -1)
{
idx = nodes[idx].out[c - 'a'];
}
else
{
while (idx > 0 && !mismatch_can_extend(idx, c - 'a'))
idx = nodes[idx].mismatch;
int next = idx;
if (mismatch_can_extend(idx, c - 'a'))
next = nodes[nodes[idx].mismatch].out[c - 'a'];
idx = next;
}
nodes[idx].cnt++;
}
}
void propagate()
{
std::vector<int> bfs_order;
std::queue<int> q;
q.push(0);
while (!q.empty())
{
int node = q.front();
q.pop();
bfs_order.push_back(node);
for (int i = 0; i < SIGMA; i++)
{
if (nodes[node].out[i] == -1)
continue;
q.push(nodes[node].out[i]);
}
}
for (int i = (int)bfs_order.size() - 1; i >= 0; i--)
nodes[nodes[bfs_order[i]].mismatch].cnt += nodes[bfs_order[i]].cnt;
}
std::vector<int> get_appearances()
{
std::vector<int> appearances(word_ptr.size(), 0);
for (int i = 0; i < (int)word_ptr.size(); i++)
appearances[i] = nodes[word_ptr[i]].cnt;
return appearances;
}
};
int main()
{
std::ifstream cin("ahocorasick.in");
std::ofstream cout("ahocorasick.out");
std::string text;
cin >> text;
int n;
cin >> n;
Aho aho;
for (int i = 0; i < n; i++)
{
std::string word;
cin >> word;
aho.insert(word);
}
aho.build();
aho.walk(text);
aho.propagate();
auto appearances = aho.get_appearances();
for (int ap : appearances)
cout << ap << '\n';
return 0;
}