P8306 【模板】字典树
题目描述
给定 \(n\) 个模式串 \(s_1, s_2, \dots, s_n\) 和 \(q\) 次询问,每次询问给定一个文本串 \(t_i\),请回答 \(s_1 \sim s_n\) 中有多少个字符串 \(s_j\) 满足 \(t_i\) 是 \(s_j\) 的前缀。
一个字符串 \(t\) 是 \(s\) 的前缀当且仅当从 \(s\) 的末尾删去若干个(可以为 0 个)连续的字符后与 \(t\) 相同。
输入的字符串大小敏感。例如,字符串 Fusu
和字符串 fusu
不同。
输入格式
本题单测试点内有多组测试数据。
输入的第一行是一个整数,表示数据组数 \(T\)。
对于每组数据,格式如下:
第一行是两个整数,分别表示模式串的个数 \(n\) 和询问的个数 \(q\)。
接下来 \(n\) 行,每行一个字符串,表示一个模式串。
接下来 \(q\) 行,每行一个字符串,表示一次询问。
输出格式
按照输入的顺序依次输出各测试数据的答案。
对于每次询问,输出一行一个整数表示答案。
输入输出样例 #1
输入 #1
3
3 3
fusufusu
fusu
anguei
fusu
anguei
kkksc
5 2
fusu
Fusu
AFakeFusu
afakefusu
fusuisnotfake
Fusu
fusu
1 1
998244353
9
输出 #1
2
1
0
1
2
1
说明/提示
数据规模与约定
对于全部的测试点,保证 \(1 \leq T, n, q\leq 10^5\),且输入字符串的总长度不超过 \(3 \times 10^6\)。输入的字符串只含大小写字母和数字,且不含空串。
说明
std 的 IO 使用的是关闭同步后的 cin/cout,本题不卡常。
分析
本题要求找到模式串中,测试串作为模式串的子串出现了多少次
改了半天 😦 ,字典树是一个树状字符数组,可以快速查找单词和子字符串,根节点是0,不包含字符,详细可以看字典树模板讲得很清楚
代码
#include<iostream>
#include<cstring>
#include<string>
#include<unordered_set>
#include<unordered_map>
using namespace std;const int N = 100010,M = 3e6 + 10;
int son[M][62],cnt[M],idx = 0;
char s[M];
inline int atn(char c) { //分开映射到不同区间if(c >= 'a' && c <= 'z') return c - 'a';if(c >= 'A' && c <= 'Z') return c - 'A' + 26;return c - '0' + 52;}void insert(char str[]) //插入字符串
{int p = 0,len = strlen(str); //p就是代表树的深度,for(int i = 0;i < len ;++i){int u = atn(str[i]); if(!son[p][u]) son[p][u] = ++idx; //如果在p深度下没有对应字符,那么创建新的字符分支,idx表示用到的字符个数p = son[p][u]; //son[p][u]代表在p深度时候u字符存在cnt[p]++; //记录该位置字符出现次数,这里由于题目要求,不是记录的字符串末尾}}int query(char str[]) { //查询字符串int p = 0,len = strlen(str);for(int i = 0;i < len ;++i) { //int u = atn(str[i]);if(!son[p][u]) return 0; //存在查询过程中的字符不存在就返回0p = son[p][u]; }return cnt[p];}int main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int T;cin >> T;while(T--) {// memset(son,0,sizeof(son)); //memset的时间是O(n),太大会超时,由于是全局变量,只用考虑改变过的部分// memset(cnt,0,sizeof(cnt)); //for(int i = 0;i <= idx; ++i) //一共用了idx个位置for(int j = 0;j < 62; ++j)son[i][j] = 0;for(int i = 0;i <= idx; ++i) cnt[i] = 0; //一样,idx = 0; //使用过后清零,不然会一直叠加下去int n,q;cin >> n >> q;while(n--) { cin >> s; insert(s); }while(q--) {cin >> s;cout << query(s) << endl; }}return 0;
}