洛谷 P8306 模板字典树
Posted zzc大魔王
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P8306 模板字典树相关的知识,希望对你有一定的参考价值。
【数据结构】字典树TrieTree图文详解_Avalon Demerzel的博客-CSDN博客
建议先看一看上面那两个网站,不透彻的可以再看我的理解一下。
由于字典树的每一个节点都是有用的,都有可能是一个单词的结尾,所以需要给每个节点打上编号,所以字典树所占的内存会非常大。
第一维大小可以直接用字符串最长长度来测试(不够再扩大)
最重要的是二维数组的含义
根据打上编号的字典树结构我们可以发现,每一个节点下面都可以跟26种情况,为了方便迭代查阅,定义二维数组为 t[当前节点编号][连接的字母]=子节点编号
即有 t[子节点编号][连接的字母]=子节点编号的编号,直接套用自己即可。
如果对应有编号,那就说明连上了,没有编号,那就是没连着。
这道题有大写字母,小写字母,数字,一共26+26+10=62种。
将其映射到二维数组中。
int getNum(char c)
if(c>='a' and c<='z')return c-'a';
else if(c>='A' and c<='Z')return c-'A'+26;
else return c-'0'+52;
根据二维数组含义实现插入。
inline void insert()
int now=0;//从根节点开始往下连接
for(int i=0;i<s.length();++i)
int k= getNum(s[i]);//得到映射
if(!t[now][k])t[now][k]=++idx;//没有这个字母的话,新建一个节点
now=t[now][k];//往下搜
cnt[now]++;//记录所有前缀,此题要用
和插入基本一样的查找。
int find()
int now=0;
for(int i=0;i<s.length();++i)
int k= getNum(s[i]);
if(!t[now][k])return 0;
now=t[now][k];
return cnt[now];
最后,由于初始化一直在用memset一直导致TLE。
原因应该是需要被初始化的空间(编号范围)远小于N,如果用memset去初始化所有空间就会超时。
所以这道题的初始化应该用for来手动赋值(for的手动赋值和memset在汇编上实现一致,但是for的范围更小,所以此处速度比memset快的多)
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e6+10;
inline void betterCinCout()
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int getNum(char c)
if(c>='a' and c<='z')return c-'a';
else if(c>='A' and c<='Z')return c-'A'+26;
else return c-'0'+52;
int T,n,q,t[N][63],idx,cnt[N];
string s;
inline void insert()
int now=0;//从根节点开始往下连接
for(int i=0;i<s.length();++i)
int k= getNum(s[i]);//得到映射
if(!t[now][k])t[now][k]=++idx;//没有这个字母的话,新建一个节点
now=t[now][k];//往下搜
cnt[now]++;//记录所有前缀,此题要用
inline void init()
for(int i=0;i<=idx;++i)
for(int j=0;j<=62;++j)
t[i][j]=0;
for(int i=0;i<=idx;++i)
cnt[i]=0;
idx=0;
int find()
int now=0;
for(int i=0;i<s.length();++i)
int k= getNum(s[i]);
if(!t[now][k])return 0;
now=t[now][k];
return cnt[now];
int main()
betterCinCout();
cin>>T;
while(T--)
init();
cin>>n>>q;
for(int i=1;i<=n;++i)
cin>>s;
insert();
for(int i=1;i<=q;++i)
cin>>s;
cout<<find()<<endl;
return 0;
洛谷P3373 模板线段树 2
P3373 【模板】线段树 2
- 47通过
- 186提交
- 题目提供者HansBug
- 标签
- 难度提高+/省选-
提交 讨论 题解
最新讨论
- 为啥WA(TAT)
题目描述
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.将某区间每一个数乘上x
3.求出某区间每一个数的和
输入输出格式
输入格式:
第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k
操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k
操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果
输出格式:
输出包含若干行整数,即为所有操作3的结果。
输入输出样例
输入样例#1:
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
输出样例#1:
17
2
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^)
样例说明:
故输出应为17、2(40 mod 38=2)
分析:参见:传送门,一模一样.
以上是关于洛谷 P8306 模板字典树的主要内容,如果未能解决你的问题,请参考以下文章