字典树、并查集适用于算法竞赛

字典树

题目:835. Trie字符串统计 - AcWing题库

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

我们用int  sun[N][26]来表示树种某个节点,假如单词hello是第一个插入的单词,那么

son[0]['h'-'a']=1;

son[1]['e'-'a']=2;

son[2][''i'-'a']=3;

son[3]['i'-'a']=4;

son[4]['o'-'i']=5;

son[0]['w'-'a']=6。就这样依次类推。

int cnt[N]来表示某节点有多少次出现。比如插入两次"hello",而'o'这个节点是5号节点,所以cnt[5]=2。

idx 表示当前使用到哪个节点了。

#include<iostream>
#include<string>
using namespace std;
const int N =100008;
int son[N][26],cnt[N],idx;
char str[N];void insert(char s[]){int p=0;for(int i=0;s[i];i++){int u=s[i]-'a';if(!son[p][u]) son[p][u]=++idx;p = son[p][u];}cnt[p]++;
}int query(char s[]){int p=0;for(int i=0;s[i];i++){int u = s[i]-'a';if(! son[p][u]) return 0;p = son[p][u];}return cnt[p];
}int main(){int n;scanf("%d",&n);for(int i=0;i<n;i++){char s[2];//指定长度为2scanf("%s%s",s,str);if(s[0]=='I'){insert(str);}else{int out = query(str);printf("%d\n",out);}}return 0;
}

并查集

题目一

836. 合并集合 - AcWing题库

一共有 n个数,编号是 1∼𝑛,最开始每个数各自在一个集合中。

现在要进行 m𝑚 个操作,操作共有两种:

  1. M a b,将编号为 𝑎 和 𝑏 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
  2. Q a b,询问编号为 𝑎 和 𝑏 的两个数是否在同一个集合中;
输入格式

第一行输入整数 𝑛 和 𝑚。

接下来 m𝑚 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。

输出格式

对于每个询问指令 Q a b,都要输出一个结果,如果 a𝑎 和 b𝑏 在同一集合内,则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤n,m≤1e5,1≤𝑛,𝑚≤1e5

输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes

  • 在计算机科学中,并查集是一种树形的数据结构,用于处理不交集的合并(union)及查询(find)问题。
  • 并查集主要是用来解决动态连通性问题的,比如查询网状图中两个节点的状态,进行数学中集合相关的操作, 如求两个集合的并集等。
其主要操作:
  • findRoot:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一个子集
  • unionElements:将两个子集合并成同一个集合

基本原理:

每一个集合用一棵树表示。树根的编号就是集合的编号,每个节点存储它的父节点,p[x]表示x的父节点。注意:只有根节点存在等式p[x]==x,其余节点均是p[x] != x。

问题:

一:如何判断树根?

答:if(p[x]==x)

二:如何求x的集合编号?

答:while(p[x] != x) x = p[x]

即依次向上找

三:如何合并两个集合?

答:如果a、b不是同一个集合,那么p[find_ancestors(a)] = find_ancestors(b);//合并,让集合a的父节点是集合b的父节点。

代码
#include<iostream>
using namespace std;const int N =100009;
int p[N],n,m;int find_ancestors(int x){//查找节点x的祖先节点+路径压缩(递归实现)if(p[x] != x) p[x] = find_ancestors(p[x]);  //只要节点的父节点不是本身(不是根节点),就递归调用让其父节点等于其父节点的祖先return p[x];// // // // 也可以用循环来做// int org =x;// while(p[x] != x){//     x = p[x];// }// while(p[org] != org){//     p[org] = x;//     org = p[org];// }// return x;
}int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) p[i] = i;//初始化,每个数都是一个单独的集合。while(m--){char op[2];int a,b;scanf("%s%d%d",op,&a,&b);if(op[0]=='M'){p[find_ancestors(a)] = find_ancestors(b);//合并,让集合a的父节点是集合b的父节点}else{if(find_ancestors(p[a]) == find_ancestors(p[b])){printf("Yes\n");}else{printf("No\n");}}}return 0;
}

题目二

给定一个包含 𝑛 个点(编号为 1∼𝑛)的无向图,初始时图中没有边。

现在要进行 𝑚 个操作,操作共有三种:

  1. C a b,在点 𝑎 和点 𝑏 之间连一条边,𝑎 和 𝑏 可能相等;
  2. Q1 a b,询问点 𝑎 和点 𝑏 是否在同一个连通块中,𝑎 和 𝑏 可能相等;
  3. Q2 a,询问点 𝑎 所在连通块中点的数量;
输入格式

第一行输入整数 𝑛 和 𝑚。

接下来 𝑚 行,每行包含一个操作指令,指令为 C a bQ1 a b 或 Q2 a 中的一种。

输出格式

对于每个询问指令 Q1 a b,如果 a𝑎 和 b𝑏 在同一个连通块中,则输出 Yes,否则输出 No

对于每个询问指令 Q2 a,输出一个整数表示点 a𝑎 所在连通块中点的数量

每个结果占一行。

数据范围

1≤n,m≤1e5,1≤𝑛,𝑚≤1e5

输入样例:
5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5
输出样例:
Yes
2
3
思路

每个连通块可以看成一个集合,开始时每个节点各自是一个集合,当两个点之间连一条边时相当于将两个集合合并。因此也可以使用并查集模板,对于查询一个连通块中节点的数量,可以在初始化时定义一个size[]数组,其只对根节点有意义,当合并时将两个连通块的size[]相加,因为起始从1开始,所以每次合并都会成功正确更新(这也是一个思想,计算个数,如果整个集合从1开始合并,最后合并一个更大的集合,那么可以用这种思想,相当于从底向上推导。)

代码
#include<iostream>
using namespace std;
const int N = 1e5+10;
int p[N],mysize[N];int find_ancestors(int x)
{if(p[x] != x) p[x] = find_ancestors(p[x]);return p[x];//避坑,这里时返回p[x],而不是x,因为x是节点编号,p[x]才是其祖宗节点的编号
}int main(){int n,m;int a,b;char str[5];scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){p[i] = i;mysize[i] =1;}while(m--){scanf("%s",str);if(str[0]=='C'){scanf("%d%d",&a,&b);int pa,pb;pa = find_ancestors(a);pb = find_ancestors(b);if(pa==pb) continue;else{mysize[pa] += mysize[pb];p[pb] = pa;}}else{if(str[1]=='1'){scanf("%d%d",&a,&b);int pa,pb;pa = find_ancestors(a);pb = find_ancestors(b);if(pa==pb){printf("Yes\n");}else{printf("No\n");}}else{scanf("%d",&a);printf("%d\n",mysize[find_ancestors(a)]);}}}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49819.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++初学者指南-6.函数对象--函数对象

C初学者指南-6.函数对象–函数对象 文章目录 C初学者指南-6.函数对象--函数对象函数对象示例&#xff1a;区间查询区间内的查找区间划分(分组) 指南标准库函数对象比较算术运算 函数对象 提供至少一个成员函数重载 operator() 的对象 class Multiplier {int m_; public:// cons…

还在用if校验参数?SpringBoot使用validation优雅实现参数校验

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru (更多精彩内容可进入主页观看) &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 目录 一、前…

鸿蒙APP架构及开发入门

1.鸿蒙系统 1.1 什么是鸿蒙 鸿蒙是一款面向万物互联时代的、全新的分布式操作系统。 在传统的单设备系统能力基础上&#xff0c;鸿蒙提出了基于同一套系统能力、适配多种终端形态的分布式理念&#xff0c;能够支持手机、平板、智能穿戴、智慧屏、车机、PC、智能音箱、耳机、…

深入解析食堂采购系统源码:打造高效食材供应链APP的核心

本篇文章&#xff0c;笔者将从系统架构、关键模块、技术选型和优化策略等方面&#xff0c;深入解析食堂采购系统的源码&#xff0c;为您揭示打造高效食材供应链APP的核心要点。 一、系统架构 食堂采购系统通常采用分层架构&#xff0c;以保证系统的可维护性和扩展性。主要包括…

Android 列表或网格形式展示大量数据:RecyclerView(二):缓存复用

一、缓存复用 为什么要了解这个呢&#xff1f;当我们rv出现卡顿&#xff0c;出现闪烁的时候&#xff0c;你应该如何优化呢&#xff1f; 为什么有时候onCreateViewHolder会被调用&#xff1f;onBindVilewHolder会被调用呢&#xff1f; visiable的使用&#xff0c;会导致重新绘制…

Linux---git工具

目录 初步了解 基本原理 基本用法 安装git 拉取远端仓库 提交三板斧 1、添加到缓存区 2、提交到本地仓库 3、提交到远端 其他指令补充 多人协作管理 windows用户提交文件 Linux用户提交文件 初步了解 在Linux中&#xff0c;git是一个指令&#xff0c;可以帮助我们做…

jionlp根据词典进行行政区划补全

背景 需要对地址数据进行行政区划补全的,可以用下面的方法,当然是有条件限制的,只限于提供本省的词典和补全本身的地址数据,否则容易错乱 效果测试 lp = LocationParser() loc = 侨英街道乐海南里170号 res = lp(loc) print(res)1、安装或者更新 python安装 pip insta…

Python爬虫技术 第18节 数据存储

Python 爬虫技术常用于从网页上抓取数据&#xff0c;并将这些数据存储起来以供进一步分析或使用。数据的存储方式多种多样&#xff0c;常见的包括文件存储和数据库存储。下面我将通过一个简单的示例来介绍如何使用 Python 爬取数据&#xff0c;并将其存储为 CSV 和 JSON 文件格…

LangChain4j-RAG高级-核心概念

RetrievalAugmentor整体概念 简单总结一下 LangChain4j中对于RetrievalAugmentor这里官方描述的比较模糊, 只在 DefaultRetrievalAugmentor章节给出来了一个灵感来源的文章(LangChain框架中的设计思路)和一个研究报告, 有兴趣可以看一下: Deconstructing RAGhttps://arxiv.o…

FRP配置内网穿透52版本以上适用

简述 适用frp配置内网穿透来说我们需要进行简单的区分&#xff0c;具有公网IP的服务器我们简称为服务端&#xff0c;内网的服务器我们可以简称为客户端&#xff0c;frp需要针对不同的服务器配置不同的文件 下载安装包 Linux下载地址 https://github.com/fatedier/frp/relea…

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…

svelte - 5. 动画

动画函数 函数作用使用场景示例引入的模块使用示例tweened运动动画,做到渐变的效果控制进度条速度svelte/motion函数:tweened(0, { duration: 400 })spring运动动画,用于频繁变化的值控制鼠标红点顺滑度svelte/motion函数:spring({ x: 50, y: 50 }, { stiffness: 0.1, damp…

华为ensp中ISIS原理与配置(超详细)

isis原理与配置 8-20字节&#xff1b; 地址组成&#xff1a;area id&#xff0c;system id&#xff0c;set三部分组成&#xff1b; system id占6个字节&#xff1b;sel占一个&#xff0c;剩下的为area id区域号&#xff1b; system id 唯一&#xff0c; 一般将router id 配…

深入学习H264和H265

目录 前言 一 什么是H264/H265&#xff1f; H.264 (MPEG-4 AVC) H.265 (HEVC) 二 为什么要学习H264和H265&#xff1f; 1. 深入理解视频压缩原理 2. 硬件优化与集成 3. 调试与故障排除 4. 持续的技术更新 三 NAL&#xff08;Network Abstraction Layer&#xff09;详解…

【前端 11】初探DOM

JavaScript 对象 - DOM 初探 在Web开发中&#xff0c;DOM&#xff08;Document Object Model&#xff0c;文档对象模型&#xff09;是一个至关重要的概念。它不仅仅是一个API&#xff0c;更是Web页面与JavaScript代码之间的桥梁&#xff0c;允许开发者通过编程的方式动态地访问…

Redis:快速键值存储的入门指南

一、什么是Redis&#xff1f; Redis&#xff0c;全称为Remote Dictionary Server&#xff0c;是一种开源的、高性能的键值&#xff08;Key-Value&#xff09;存储系统。与传统的关系型数据库不同&#xff0c;Redis将数据主要存储在内存中&#xff0c;因此能够提供极低延迟的数…

【Unity2D 2022:UI】TextMeshPro组件无法显示中文

在Unity中创建了一个预制体Card&#xff0c;上面挂载了一些Text Mesh Pro组件用来显示卡牌信息。但是在输入文字后&#xff0c;发现无法显示中文&#xff1a; 解决方法如下&#xff1a; 一、导入字体文件&#xff08;ttf格式&#xff09;和常用字字集&#xff08;txt格式&…

Linux--Socket编程UDP

前文&#xff1a;Socket套接字编程 UDP协议特点 无连接&#xff1a;UDP在发送数据之前不需要建立连接&#xff0c;减少了开销和发送数据之前的时延。尽最大努力交付&#xff1a;UDP不保证可靠交付&#xff0c;主机不需要维持复杂的连接状态表。面向报文&#xff1a;UDP对应用层…

算法:[递归/搜索/回溯]二叉树的深搜

目录 题目一&#xff1a;计算布尔二叉树的值 题目二&#xff1a;求根节点到叶节点数字之和 题目三&#xff1a;二叉树剪枝 题目四&#xff1a;验证二叉搜索树 题目五&#xff1a;二叉搜索树中第k小的元素 题目六&#xff1a;二叉树的所有路径 题目一&#xff1a;计算布尔…

【C语言】宏定义常量加 ; 的错误

我在使用宏定义常量定义二维数组的时候&#xff0c;编译器报错&#xff1a;应输入“]”&#xff0c;如下&#xff1a; 原因是宏定义不是C语言规定的语句&#xff0c;它的结尾不加 ; 。在上图的 int mine[EASY_ROWS][EASY_COLS]; 中&#xff0c;把 EASY_ROWS 替换为了 9;2; &…