Submission #1334622

#TimeUsernameProblemLanguageResultExecution timeMemory
1334622cnam9Selling RNA Strands (JOI16_selling_rna)C++20
100 / 100
329 ms232076 KiB
#include <iostream>
#include <string>
#include <vector>
#include <math.h>

using namespace std;

constexpr int N = 1e5 + 5;
constexpr int L = 2e6 + 5;
constexpr int MAX_NODES = static_cast<int>(L + L * log2(N));

struct Node;

struct NodePtr {
    int id;

    NodePtr() { }
    NodePtr(int id) : id(id) { }
    operator int() const { return id; }

    Node *operator->() const;
    NodePtr operator[](const string &s) const;
};

struct Node {
    int count;
    NodePtr children[4];
};

Node trie[MAX_NODES];
int num_nodes = 0;

Node *NodePtr::operator->() const {
    return &trie[id];
}

string chains[L];
vector<pair<string, int>> queries[L];
int answer[N];

void merge(NodePtr node1, NodePtr node2) {
    node1->count += node2->count;

    for (int i = 0; i < 4; i++) {
        if (!node2->children[i]) continue;

        if (!node1->children[i]) {
            node1->children[i] = ++num_nodes;
        }
        merge(node1->children[i], node2->children[i]);
    }
}

// {trie root, trie size}
pair<NodePtr, int> dfs(NodePtr node) {
    int root = 0;
    int size = 0;

    for (NodePtr &child : node->children) {
        if (!child) continue;

        auto [child_root, child_size] = dfs(child);

        if (child_size > size) {
            size = child_size;
            root = child_root;
        }

        child = child_root;
    }

    size -= num_nodes;

    if (!root) {
        root = ++num_nodes;
    }

    // cout << "hi, i'm " << node << " and my root is " << root << endl;

    for (NodePtr child_root : node->children) {
        if (!child_root || child_root == root) continue;
        merge(root, child_root);
    }

    if (node->count) {
        // cout << "heyy!! " << node << ": " << chains[node] << endl;
        NodePtr node2 = root;
        node2->count += node->count;

        for (auto it = chains[node].rbegin(); it != chains[node].rend(); ++it) {
            int dir = ((*it) >> 1) & 3;
            if (!node2->children[dir]) {
                node2->children[dir] = ++num_nodes;
            }
            node2 = node2->children[dir];
            node2->count += node->count;
        }
        // cout << "node2 " << node2 << " received " << node->count << endl;
    }

    for (const auto &[q, i] : queries[node]) {
        // cout << "answering " << chains[node] << ' ' << q << endl;
        NodePtr node2 = root;
        for (auto it = q.rbegin(); it != q.rend(); ++it) {
            int dir = ((*it) >> 1) & 3;
            if (!node2->children[dir]) {
                goto next_query;
            }
            node2 = node2->children[dir];
        }
        answer[i] = node2->count;
    next_query:
        ;
    }

    size += num_nodes;
    return {root, size};
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    // freopen("input.txt", "r", stdin);

    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; i++) {
        string s;
        cin >> s;

        NodePtr node = 0;

        for (char c : s) {
            int dir = (c >> 1) & 3;
            if (!node->children[dir])
                node->children[dir] = ++num_nodes;
            node = node->children[dir];
        }

        node->count++;
        chains[node] = s;
    }

    for (int i = 1; i <= m; i++) {
        string p, q;
        cin >> p >> q;

        NodePtr node = 0;

        for (char c : p) {
            int dir = (c >> 1) & 3;
            if (!node->children[dir]) {
                answer[i] = 0;
                goto next;
            }
            node = node->children[dir];
        }

        chains[node] = p;
        queries[node].emplace_back(q, i);
    next:
        ;
    }

    dfs(NodePtr(0));


    for (int i = 1; i <= m; i++) {
        cout << answer[i] << '\n';
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...