Submission #1273611

#TimeUsernameProblemLanguageResultExecution timeMemory
1273611trvhungSelling RNA Strands (JOI16_selling_rna)C++20
100 / 100
875 ms606224 KiB
#include <bits/stdc++.h>
// #include <ext/rope>
// #include <ext/pb_ds/assoc_container.hpp>

// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;

// #define   ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define            ll long long
#define           ull unsigned long long
#define            ld long double
#define            pb push_back
#define  bit(mask, i) ((mask >> i) & 1)
#define            el '\n'
#define             F first
#define             S second

template <class X, class Y> bool maximize(X &x, const Y &y) { return (x < y ? x = y, 1 : 0); }
template <class X, class Y> bool minimize(X &x, const Y &y) { return (x > y ? x = y, 1 : 0); }

const int INF = 1e9;
const ll LINF = 1e18;
const int MOD = 1e9 + 7;
const int MULTI = 0;
const ld eps = 1e-9;
const int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}; // R D L U
const int ddx[4] = {-1, 1, 1, -1}, ddy[4] = {1, 1, -1, -1}; // UR DR DL UL
const char cx[4] = {'R', 'D', 'L', 'U'};
const ll base = 31;
const int nMOD = 2;
const ll mods[] = {(ll)1e9 + 10777, (ll)1e9 + 19777, (ll)1e9 + 3, (ll)1e9 + 3777};

const int N = 1e5 + 5;
const int MAX = 2e6 + 5;
int n, m, curNode, pw[nMOD][N], hashQ1[N], res[N], ti[MAX], to[MAX], timeDfs;
string s[N], p[N], q[N];
pair<int, int> hashQ[N];
vector<int> at[N], adj[MAX];
vector<pair<int, int>> comp;

struct query {
	int idHash, idQuery;
	bool operator < (const query &other) const {
		return idHash < other.idHash;
	}
} Q[N];

struct node {
	node *child[26];
	int id, h, cnt;
	node() {
		for (int i = 0; i < 26; ++i) child[i] = nullptr;
		id = h = cnt = 0;
	}
};

node *root = new node();

void add(string &x) {
	node *u = root;
	for (auto c: x) {
		int k = c - 'A';
		
		if (u -> child[k] == nullptr) {
			u -> child[k] = new node();
			u -> child[k] -> id = ++curNode;
			u -> child[k] -> h = u -> h + 1;
			adj[u -> id].push_back(u -> child[k] -> id);
		}

		u = u -> child[k];
		u -> cnt++;
	}
}

void trav(string &x) {
	vector<char> path;
	node *u = root;

	for (auto c: x) {
		int k = c - 'A';
		path.push_back(c);
		u = u -> child[k];
	}

	pair<int, int> H = make_pair(0, 0);
	int len = 0;
	reverse(path.begin(), path.end());

	for (auto c: path) {
		H.F = (1LL * (c - 'A' + 1) * pw[0][len] + H.F) % mods[0];
		H.S = (1LL * (c - 'A' + 1) * pw[1][len] + H.S) % mods[1];

		int pos = lower_bound(comp.begin(), comp.end(), H) - comp.begin();
		if (pos < (int) comp.size() && comp[pos] == H)
			at[pos + 1].push_back(u -> id);

		len++;
	}
}

void precalc() {
	for (int i = 0; i < nMOD; ++i) {
		pw[i][0] = 1;
		for (int j = 1; j < N; ++j)
			pw[i][j] = 1LL * pw[i][j - 1] * base % mods[i];
	}
}

void calcHash(string &x, pair<int, int> &H) {
	int len = (int) x.size();
	for (int i = 1; i <= len; ++i) {
		H.F = (1LL * H.F * base + x[i - 1] - 'A' + 1) % mods[0];
		H.S = (1LL * H.S * base + x[i - 1] - 'A' + 1) % mods[1];
	}
}

void compressHashQ() {
	for (int i = 1; i <= m; ++i)
		comp.push_back(hashQ[i]);

	sort(comp.begin(), comp.end());
	comp.resize(unique(comp.begin(), comp.end()) - comp.begin());

	for (int i = 1; i <= m; ++i)
		hashQ1[i] = lower_bound(comp.begin(), comp.end(), hashQ[i]) - comp.begin() + 1;
}

void dfs(int u) {
	ti[u] = ++timeDfs;
	for (int v: adj[u])
		dfs(v);
	to[u] = timeDfs;
}

struct BIT {
	int bit[MAX];

	void update(int id, int v) {
		for (; id <= curNode; id += id & -id)
			bit[id] += v;
	}

	int get(int id) {
		int res = 0;
		for (; id > 0; id -= id & -id)
			res += bit[id];
		return res;
	}

	int getRange(int l, int r) {
		if (l > r) return 0;
		return get(r) - get(l - 1);
	}
} bit;

void updateAns(int i) {
	node *u = root;
	for (auto c: p[i]) {
		int k = c - 'A';
		if (u -> child[k] == nullptr) return;
		u = u -> child[k];
	}
	res[i] = bit.getRange(ti[u -> id], to[u -> id]);
}

void solve() {
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		cin >> s[i];
		add(s[i]);
	}

	precalc();
	for (int i = 1; i <= m; ++i) {
		cin >> p[i] >> q[i];
		calcHash(q[i], hashQ[i]);
	}

	compressHashQ();

	for (int i = 1; i <= n; ++i)
		trav(s[i]);

	dfs(0);

	for (int i = 1; i <= m; ++i) {
		Q[i].idHash = hashQ1[i];
		Q[i].idQuery = i;
	}

	sort(Q + 1, Q + 1 + m);
	int ptr = 1;
	curNode++;

	while (ptr <= m) {
		for (int x: at[Q[ptr].idHash]) 
			bit.update(ti[x], 1);

		int j = ptr;
		updateAns(Q[ptr].idQuery);
		while (j < m && Q[j + 1].idHash == Q[j].idHash) {
			updateAns(Q[++j].idQuery);
		}

		for (int x: at[Q[ptr].idHash]) 
			bit.update(ti[x], -1);

		ptr = j + 1;
	}

	for (int i = 1; i <= m; ++i)
		cout << res[i] << el;
}

signed main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    if (!MULTI) solve();
    else {
        int test; cin >> test;
        while (test--) solve();
    }
    
    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...