Submission #366699

#TimeUsernameProblemLanguageResultExecution timeMemory
366699RainbowbunnySelling RNA Strands (JOI16_selling_rna)C++17
100 / 100
910 ms614988 KiB
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <ctime>
#include <cassert>
#include <complex>
#include <chrono>
#include <random>
#include <bitset>
#include <utility>

int convert(char x)
{
	if(x == 'A')
	{
		return 0;
	}
	else if(x == 'G')
	{
		return 1;
	}
	else if(x == 'C')
	{
		return 2;
	}
	else if(x == 'U')
	{
		return 3;
	}
	assert(false);
}

struct node
{
	int nxt[4];
	int cnt;
	node()
	{
		for(int i = 0; i < 4; i++)
		{
			nxt[i] = -1;
		}	
		cnt = 0;
	}
};

struct Trie
{
	std::vector <node> Tree;
	Trie()
	{
		Tree.resize(1);	
	}	
	void Add(std::string &s)
	{
		int node = 0;
		Tree[node].cnt++;
		for(auto x : s)
		{
			int tmp = convert(x);
			if(Tree[node].nxt[tmp] == -1)
			{
				Tree[node].nxt[tmp] = (int)Tree.size();
				Tree.emplace_back();
			}
			node = Tree[node].nxt[tmp];
			Tree[node].cnt++;
		}
	}
	int Count(std::string &s)
	{
		int node = 0;
		for(auto x : s)
		{
			int tmp = convert(x);
			if(Tree[node].nxt[tmp] == -1)
			{
				return 0;
			}
			node = Tree[node].nxt[tmp];
		}
		return Tree[node].cnt;
	}
};

int timer;
std::vector <int> tin, tout;
std::vector <std::pair <int, int> > Position;
Trie Prefix;
Trie IT[1 << 19 | 5];

int n;
std::string s[100005];

int q;

void DFS(int node)
{
	timer++;
	tin[node] = timer;
	for(int i = 0; i < 4; i++)
	{
		if(Prefix.Tree[node].nxt[i] != -1)
		{
			DFS(Prefix.Tree[node].nxt[i]);
		}
	}
	tout[node] = timer;
}

void Cal()
{
	tin.resize(Prefix.Tree.size());
	tout.resize(Prefix.Tree.size());
	DFS(0);	
	for(int i = 0; i < n; i++)
	{
		int node = 0;
		for(auto x : s[i])
		{
			node = Prefix.Tree[node].nxt[convert(x)];
		}
		Position.emplace_back(tin[node], i);
	}
	std::sort(Position.begin(), Position.end());
}

void Build(int node, int l, int r)
{
	
	for(int i = l; i <= r; i++)
	{
		IT[node].Add(s[Position[i].second]);
	}
	if(l != r)
	{
		int mid = (l + r) >> 1;
		Build(node << 1, l, mid);
		Build(node << 1 | 1, mid + 1, r);
	}
}

int Get(int node, int l, int r, int L, int R, std::string &s)
{
	if(L > r or R < l)
	{
		return 0;
	}
	if(L <= l and r <= R)
	{
		return IT[node].Count(s);
	}
	int mid = (l + r) >> 1;
	return Get(node << 1, l, mid, L, R, s) + Get(node << 1 | 1, mid + 1, r, L, R, s);
}

void BuildMergeSortTree()
{
	for(int i = 0; i < n; i++)
	{
		reverse(s[i].begin(), s[i].end());
	}
	Build(1, 0, n - 1);
}

int main()
{
	std::ios_base::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin >> n >> q;
	for(int i = 0; i < n; i++)
	{
		std::cin >> s[i];
		Prefix.Add(s[i]);
	}
	Cal();
	BuildMergeSortTree();
	while(q--)
	{
		std::string pre, suf;
		std::cin >> pre >> suf;
		reverse(suf.begin(), suf.end());
		int node = 0;
		for(auto x : pre)
		{
			int tmp = convert(x);
			if(Prefix.Tree[node].nxt[tmp] == -1)
			{
				node = -1;
				break;
			}
			node = Prefix.Tree[node].nxt[tmp];
		}
		if(node == -1)
		{
			std::cout << 0 << '\n';
		}
		else
		{
			int l = tin[node], r = tout[node];
			l = lower_bound(Position.begin(), Position.end(), std::make_pair(l, 0)) - Position.begin();
			r = upper_bound(Position.begin(), Position.end(), std::make_pair(r, (int)1e9)) - Position.begin() - 1;
			std::cout << Get(1, 0, n - 1, l, r, suf) << '\n';
		}
	}
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...