trie树(字典树) 洛谷 P3879 [TJOI2010] 阅读理解

洛谷P3879 [TJOI2010] 阅读理解 P3879 [TJOI2010] 阅读理解英语老师留了 NNN 篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。对于每个生词输出一行,统计其在哪几篇短文中出现过,并按从小到大输出短文的序号,序号不应有重复,序号之间用一个空格隔开(注意第一个序号的前面和最后一个序号的后面不应有空格(这个最后的空格好像没有判[doge]))。如果该单词一直没出现过,则输出一个空行。1≤M≤1041\le M\le 10^41≤M≤104,1≤N≤103 阅读详情

一、什么是字典树

我之前发布了关于 KMP 算法实现的文章,Trie树和KMP算法都是用于字符串匹配的算法,它们可以在一定程度上互相补充和优化。👇👇👇

洛谷P3375 【模板】KMP_洛谷 p3375-优快云博客icon-default.png?t=N7T8https://blog.youkuaiyun.com/ByteMaster_/article/details/141028724?spm=1001.2014.3001.5501KMP 算法的原理在上述博客中已经讲清,本篇博客用来讲解trie树算法

字典树 正如它字面意思,把字符串按照字典的顺序存放在一棵树上,通过每个单词和其他单词的公共前缀把他们连接起来,如图所示

如图所示   

5  : apple  12 : application  15  : appear  18  : cat   24 : capaticity  27 : bus 32 : banana   

二、如何构建字典树

构建这样的字典多叉树 可以用来进行 快速插入和查询字符串的操作

节点的编号各不相同,根节点的编号为0 ,其他节点用来标识路径 还可以用来记录插入单词的次数, 边用来表示具体的字符

trie树用来维护字符串的集合 支持两种操作 

1.向集合中插入一个字符串,void insert(string s)

2.在集合中查询一个字符串,int query(string s)

下面我们来看如何用代码实现此过程

1、insert的实现

insert的实现,需要用到

①儿子数组 ch[p][j]

代表的是存储从节点p沿着j这条边走到的节点

ch[i][p]中 p 的值代表的是 26 个小写字母的映射(a~z,用它们的ASCII值减去‘a'表示)

例如 ch[0][2]=16 代表的就是原图中的 从 0 这个节点走c这条边(c的映射值是2)走到16这个节点

或者说是 节点 0 和 节点 16 之间的字符是 'c'

②计数数组 cnt[p] 代表以p为结尾的单词的插入次数

③节点编号 idx 用来给每个节点编号

插入单词的过程如下

1.空的 trie 树的节点为 0 

2.指针p按照所要插入的单词的每一个字符的顺序在trie树上游历, 如果对应的此个儿子节点不为 0 (即ch[p][s[i]-'a']!=0),此时证明  当前p所在位置  与  当前字符对应的s[i]-'a'这条边  所连接的儿子已经存在,无需再插入,p走向该儿子

比如在已经插入好 cat 时,想插入 cate ,指针 p 指向2这个节点,然而ch[2][19]已经为3(2和3之间有 t 的映射 19 这条边),此时 p 直接指向 3 进行下一步即可,无需再创建新的儿子了

3.若对应的儿子节点为0(即 ch[p][s[i]-'a']==0),证明当前 p 所在位置 与 当前字符对应的s[i]-'a'这条边 所连接的儿子节点还不存在,创建这个儿子节点,后走向儿子节点

此时 p 指向 3 这个节点,由于ch数组的初始化为0 所以ch[3][4]的值为0 ,说明当前儿子不存在,所以需要做的就是,创建儿子,也就是 令 ch[3][4] 为4(节点3 和 节点4 之间有 e 的映射 4 这条边),然后

4.再用cnt数组记录插入单词的次数

代码实现如下

void insert(string s)
{
	int p = 0;
	for (int i = 0; i < s.size(); i++)
	{
		int j = s[i] - 'a';//每个字符的映射值
		if (trie[p][j] == 0) trie[p][j] = ++id;//创建儿子,且id加1
		p = trie[p][j];//p走向儿子节点
	}
	cnt[p]++;//该单词记录完,cnt[p]加1,表示单词次数
}

2、query的实现

query用来查询这个字符串的出现次数,基本逻辑与 insert 类似

也是一个 p 指针在多叉树上游历,按照字符串 s 的每个字符的内容看 ch[p][s[i]-'a'] 的值,

1.ch[p][s[i]-'a'] 为 0 说明该单词在p所在位置处即断开,没构成完整的目标 s 字符串,所以cnt的值为0     此时直接返回 0 代表没有出现过目标单词

2.如果 ch[p][s[i]-'a'] 不为 0 说明当前目标字符串 在p所在位置对应的字符已经存在,p走向下一个位置(当前节点的下一个节点),继续重复判断

3.最后返回 cnt[p] ,p走向最终位置 ,cnt[p]为该单词的出现次数

代码实现如下

int query(string s){
	int p = 0;
	for(int i =0; i<s.size();i++){
		int j  = s[i]-'a';//当前字符的映射值
		if (ch[p][j] == 0) return 0;//此单词不存在
		p = ch[p][j];//指向下一个位置
	}
	return cnt[p];//返回出现次数
}

三、洛谷 P3879 [TJOI2010] 阅读理解

模板题

P3879 [TJOI2010] 阅读理解 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P3879

题目描述

英语老师留了 N 篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。

输入格式

第一行为整数 N ,表示短文篇数,其中每篇短文只含空格和小写字母。

按下来的 N 行,每行描述一篇短文。每行的开头是一个整数 L ,表示这篇短文由 L 个单词组成。接下来是 L 个单词,单词之间用一个空格分隔。

然后为一个整数 M ,表示要做几次询问。后面有 M 行,每行表示一个要统计的生词。

输出格式

对于每个生词输出一行,统计其在哪几篇短文中出现过,并按从小到大输出短文的序号,序号不应有重复,序号之间用一个空格隔开(注意第一个序号的前面和最后一个序号的后面不应有空格)。如果该单词一直没出现过,则输出一个空行。

输入输出样例

输入 #1

3
9 you are a good boy ha ha o yeah
13 o my god you like bleach naruto one piece and so do i
11 but i do not think you will get all the points
5
you
i
o
all
naruto

输出 #1

1 2 3
2 3
1 2
3
2

说明/提示

对于 30%的数据, 1≤M≤10^3 1≤M≤10^3 。

对于 100%的数据,1≤M≤10^41≤M≤10^4,1≤N≤10^31≤N≤10^3 。

每篇短文长度(含相邻单词之间的空格)≤5×10^3字符,每个单词长度 ≤20 字符。

每个测试点时限 2 秒。

根据代码的模块化理论,我们可以在insert函数和query中增加上输入功能,使得代码看着更加整洁。 

通过阅读题目,我们可以知道 共输入 N 篇文章,然后最后询问 M 次,那么我们需要想办法标记下是第几篇文章出现的我们需要查找的单词,从上述的trie树的模板代码中,我们看到有个数组就是用来记录单词出现的次数(以及位置)的,那就是 cnt 数组

那么我们怎么可以让 cnt 数组在可以记录单词出现次数(以及位置)的基础上,再记录下单词在哪一篇文章出现呢,那就需要给 cnt 数组增加一维,增加的那一维用来记录单词所出现的文章的序号

即 cnt[p][t]==1 代表单词末尾的序号为 p ,它在 第 t 篇文章中出现

有了这个,我们就解决了单词在哪一篇文章中出现的问题

//P3879 [TJOI2010] 阅读理解

#include <bits/stdc++.h>
using namespace std;
int N,L,M;
int trie[500010][26];
bool cnt[500010][1333];
string s;
int id=0;//⭐
void insert(int t){
	cin>>s;
	int p = 0;
	for(int i = 0;i<(int)s.length();i++){
		int x =s[i]-'a';
		if(trie[p][x]==0) trie[p][x]=++id;
		p = trie[p][x];
	}
	cnt[p][t]=1;//单词再在第t篇文章出现
}
void find (){
	cin>>s;
	int p  = 0,f=1;//f用来标记
	int l = s.length();
	for(int i =0;i<l;i++){
		int x = s[i]-'a';
		if(trie[p][x]==0){
			f=0;//如果f等于0 代表单词没有在文章中找到 或者找到了一部分
			    //剩下的断了
			break;
		}
		p = trie[p][x];
	}
	if(f){//只有f==1时,代表单词在所有文章中出现过
	for(int i = 1;i<=N;i++){
		if(cnt[p][i]==1)
			cout<<i<<" ";
	}
	}
	cout<<endl;//f==0时 表明单词没有出现过 直接跳转到这 输出换行
}
int main(){
	cin>>N;//N篇文章
	for(int i = 1;i<=N;i++){
		cin>>L;//L个单词
		for(int j = 1 ;j<=L;j++){
			insert(i);
		//在第i篇文章中依次输入L个单词
		//这是第 j 个
		}
	}
	cin>>M;
	for(int i = 1;i<=M;i++){

		find();//查找单词 在find内部输入
	}
	return 0;
}

洛谷 P3879 [TJOI2010]阅读理解(字典树) 一、题目描述 题目描述 英语老师留了N篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。 输入格式 第一行为整数N,表示短文篇数,其中每篇短文只含空格和小写字母。 按下来的N行,每行描述一篇短文。每行的开头是一个整数L,表示这篇短文由L个单词组成。接下来是L个单词,单词之间用一个空格分隔。 然后为一个整数M,表示要做几次询问... 阅读详情

相关推荐

HDFView安装及使用教程

简介:直接用记事本打开hdf5文件的话,是一团乱码。HDFView是用来查看hdf5文件的软件,可以免费使用,好多人都有闪退的情况,这是因为没有添加环境变量。

qq_43722079的博客 7万+

【洛谷刷题笔记】P3879 [TJOI2010] 阅读理解

P3879 阅读理解 刷题笔记

m0_66420734的博客 541

关于卷积过程中通道数如何变化问题

对卷积操作前后通道数问题进行解释,输出通道数=卷积核的个数。

你好,明天,,的博客 4315

map集合——阅读理解(洛谷 P3879)

直接用map<string,vecotr<int> > 代替这题里的trie树,注意开map的时候后面两个> >之间要有一个空格。

青春无问西东 岁月自成芳华 1754

UCD9081EVM电源时序管理:硬件配置与GUI操作全解析

电源时序管理是复杂电子系统设计的核心环节,它通过精确控制多路电源的上电/下电顺序,确保核心芯片免受浪涌电流或电压倒灌的损害。其原理基于状态机逻辑与电压监控,技术价值在于将硬连线时序转化为可编程配置,极大提升了系统可靠性与设计灵活性。在服务器、通信设备、工控系统等高可靠性应用场景中,时序控制器是实现稳定启动与故障保护的关键。本文以德州仪器UCD9081评估模块为例,深入剖析其硬件跳线配置与图形用户界面操作,涵盖I2C地址设置、电压监控分压计算、时序条件与故障响应策略等工程实践要点,帮助工程师快速掌握这一电源时

weixin_42696271的博客 302

博流BL602开发二 环境搭建与固件烧录实战

本文详细介绍了博流BL602 RISC-V芯片开发环境的搭建与固件烧录全流程。从Linux/WSL系统选择、RISC-V工具链配置、SDK获取,到编译首个Wi-Fi示例并生成固件镜像,再到通过命令行或图形化工具完成烧录及串口测试,提供了完整的实战指南和常见问题解决方案。

weixin_29175469的博客 449

【题解】洛谷P3879 阅读理解(trie树)

新学了字典树算法,这个可以算是一个模板吧 在有n个单词的字典中 对m个单词询问是否在此字典里。对于这个问题,我们可以通过构建字典树来解决。 trie树的思路就是对于n个单词,我们开一个数组to[maxn][26],代表编号为maxn、字母编号为x的编号(我在说啥。。。);具体思路就是构建一棵长成这样的树并记录其编号 然后对于读入的每个单词,我们对于其末尾编号开一个b数组记录下来代表一个单...

Rem_Inory的博客 646

ccproxy 6.61 注册机(纯绿/傻瓜/真正去除线程限制)

导读:   软件介绍   1、 CCPROXY 6.61 注册机(纯绿/傻瓜/真正去除线程限制)   ***前言,这次的升级官方改动不大,据说只是为了不被某些软件当病毒***   附件包中解压即免安装版,CcREGTOOLFF.exe为注册机。   本人继续向大家隆重推出《CCPROXY6.61哎呀……破解版》   还是那个提示:   在此之前,本人还是那句老话想提示大家,CCPROXY是

i53nd的专栏 1万+

洛谷——P3879 [TJOI2010] 阅读理解(STL:hash+set,c++)

对于每个生词输出一行,统计其在哪几篇短文中出现过,并按从小到大输出短文的序号,序号不应有重复,序号之间用一个空格隔开(注意第一个序号的前面和最后一个序号的后面不应有空格)。如果该单词一直没出现过,则输出一个空行。篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。,表示短文篇数,其中每篇短文只含空格和小写字母。行,每行描述一篇短文。每行的开头是一个整数。个单词,单词之间用一个空格分隔。行,每行表示一个要统计的生词。,表示要做几次询问。

2301_77012063的博客 1409

微腔光频梳仿真入门:MATLAB求解LLE方程全流程解析

光学频率梳在精密测量、光通信和微波光子学中有着广阔应用,而微环谐振腔中的Kerr非线性与四波混频效应能够紧凑地产生宽带梳齿。仿真这类系统的核心是求解Lugiato-Lefever方程(LLE),但直接从物理参数到数值代码往往让初学者无从下手。本文从微腔光频梳的物理图像出发,介绍LLE方程的推导与归一化方法,并重点讲解MATLAB数值实现的两种思路:基于ode45的频域耦合方程组求解与分裂步长RK4IP方法。同时讨论失谐扫描、孤子态识别、参数稳定性边界,以及如何将真实器件参数换算为无量纲仿真参数。无论你是刚接

weixin_32325225的博客 291

<IBM DB2>《DB2 官方监控脚本 2022版本》

DB2 监控脚本

Else 的博客 670

洛谷 P3879 [TJOI2010]【阅读理解】

题目描述 英语老师留了N篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过。 输入输出格式 输入格式: 第一行为整数N,表示短文篇数,其中每篇短文只含空格和小写字母。 按下来的N行,每行描述一篇短文。每行的开头是一个整数L,表示这篇短文由L个单词组成。接下来是L个单词,单词之间用一个空格分隔。 然后为一个整数...

weixin_30919235的博客 201

Python白色飘雪(完整代码)

Python绘制白色飘雪动画的完整代码。

AIGC 3万+

Trie树

插入:插入一个字符串时,令一个指针P指向根节点,依次扫描待插入字符串中的每个字符c。如果指针P的c字符指针指向一个已经存在的节点Q的时候,令P=Q。如果P的c字符指针指向空,则新建一个节点Q,令P的c字符指针指向Q,然后令P=Q。扫描完毕后,若当前节点未被标记为一个字符串的末尾,则不存在,否则存在。最简单的思路就是输入的时候把每一个单词插入Trie中,然后在查找生词的时候如果出现标记位置,最后每个生词分别输出即可。1.利用字符串的公共前缀来减少查询时间,减少无谓的字符串比较,查询效率比哈希表高。

linzhi6236的博客 133

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

字典树模板+位运算

trie树板子题,稍微有一丢丢不一样,套用字典树模板稍加修改就能过。

xxx_jsu的博客 539

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Trie——字典树

Trie树几个练手的题目,值得一试,难度都不大

萌新的博客 228

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

洛谷试炼日记(manacher和trie树)(解题报告)

文章目录**manacher**P4555 [国家集训队]最长双回文串P1659 [国家集训队]拉拉队排练**Trie字典树**P3879 [TJOI2010]阅读理解P2292 [HNOI2004]L语言P2922 [USACO08DEC]Secret Message GP3065 [USACO12DEC]First! G manacher P4555 [国家集训队]最长双回文串 题目链接 思路:最开始只有一个n^2的思路,不用写都知道会T 看了大佬的思路之后恍然大悟 在求以位置i为中心的最大回文串长度时

juruo_c的博客 301

【洛谷】 P3879 [TJOI2010]阅读理解

trie树 二维数组隐式越界问题

说文科技,做有态度的研究。 804

P3879 [TJOI2010] 阅读理解- 字典树

。

m0_75129175的博客 468

【字典树】【Trie】P3879 [TJOI2010] 阅读理解

P3879 [TJOI2010] 阅读理解 字典树写法 参考1 参考2 bitset用法 854ms/45.96MB #include<bits/stdc++.h> #define FOR(i,a,b) for(int i=(a);i<=(b);++i) using namespace std; int nex[300007][26],n,cnt=0; bitset<1001> b[500007];//bool b[500007][1001]; void insert(ch

追殇 | Blog 573

P3879 [TJOI2010] 阅读理解 题解

一定要小心MLE!

KJM666的博客 538

洛谷P3879 [TJOI2010] 阅读理解(c嘎嘎)

首先定义一个string映射到set的map来统计一个单词在哪几篇短文中出现过,最后读入查询的单词直接输出即可,第一种方法是tire字典树,之前学过(这道题也算是复习下),下面介绍下tire字典树。有时需要标记插入进 trie 的是哪些字符串,每次插入完成时在这个字符串所代表的节点处打上标记即可。可以发现,这棵字典树用边来代表字母,而从根结点到树上某一结点的路径就代表了一个字符串。字符指向的下一个结点,或着说是结点。:介绍两种方法,第一种还是简单粗暴的。代表的字符串后面添加一个字符。形成的字符串的结点。

2302_79431881的博客 762

Turtle Puzzle: Rearrange and Negate(Round 929)

【代码】Turtle Puzzle: Rearrange and Negate(Round 929)

GordrnGhost的博客 878

P3879 [TJOI2010]阅读理解(Trie)

P3879 [TJOI2010]阅读理解(Trie) 比较水,就是找一下模式串在哪些文本串里出现过,并且按顺序输出出现过的序号。 用个set搞下就可以了。 code // Problem: P3879 [TJOI2010]阅读理解 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P3879 // Memory Limit: 125 MB // Time Limit: 2000 ms // Date: 2021-07-06 16:11:55

Harris-H的博客 533

Trie树(字典树)//洛谷P1481+洛谷P2580

第一行——咕咕咕。 第二行——慢慢学呗,还能离咋地。 Trie树:又称字典树,前缀树。是一种通过增加空间复杂度来减少时间复杂度的结构。其特点是根节点为空,其余节点存一个字符,节点与节点之间的路径是一个字符(一般是用于字符串)。 建树:令根节点为空,从该点出发,将新的字符串上的字符一个个加入,未出现过即直接相连,出现过找到最末尾的共享字符,连接即可。 性质:1.从根节点到某节点的路径即...

MoonLight_月亮 1035

P3879 [TJOI2010] 阅读理解(详解)c++

【代码】P3879 [TJOI2010] 阅读理解(详解)c++

weixin_73266891的博客 483
上一篇: 动态规划之0-1背包问题&&完全背包问题
下一篇: C++实现顺序表操作(实验2—作业)
ByteMaster_
博客等级 码龄3年 328粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值