数据结构·字典树

字典树trie

顾名思义,在一个字符串的集合查询某个字符串是否存在树形结构
树存储方式上用的是结构体数组,类似满二叉树的形式。

模板

定义结构体和trie

  • 结构体必须的内容:当前结点的字符,孩子数组
  • 可选:end用于查询,repeat用于统计。
typedef struct node {char c;int children[30] = {0};int end = 0, repeat = 0;
};
vector<node>trie;
node root;
trie.push_back(root);

建树三部曲

  • 不好理解的可能就是这个fa,用于表示当前的父节点是谁
  • 查询结点是否存在于父节点的孩子中:if (!trie[fa].children[idx])
  • 没有存在则添加结点:创建新下标int new_idx = trie.size(),父节点的孩子添加该下标。

			int new_idx = trie.size();trie[fa].children[idx] = new_idx;node x;x.c = s[i];if (i == s.size() - 1) {x.end = 1;}trie.push_back(x);
  • 父节点变为子节点:fa = trie[fa].children[idx]
void build(string s) {int fa = 0;for (int i = 0; i < s.size(); i++) {int idx = s[i] - 'a';if (!trie[fa].children[idx]) {int new_idx = trie.size();trie[fa].children[idx] = new_idx;node x;x.c = s[i];if (i == s.size() - 1) {x.end = 1;}trie.push_back(x);fa = new_idx;}else {if (i == s.size() - 1) {trie[fa].end = 1;}fa = trie[fa].children[idx];}}
}

字符串的查询

  • 从父亲结点一直遍历到叶子结点,最后i==s.size()-1时特判end是否为end==true?即可
  • 与建树过程几乎完全一致
void query(string s) {int fa = 0;for (int i = 0; i < s.size(); i++) {int idx = s[i] - 'a';if (!trie[fa].children[idx]) {cout << "WRONG" << endl;return;}else {fa = trie[fa].children[idx];if (i == s.size() - 1) {if (trie[fa].repeat) {cout << "REPEAT" << endl;}else {if (trie[fa].end) {trie[fa].repeat = 1;cout << "OK" << endl;}else cout << "WRONG" << endl;}}}}
}

打印字典树

void print_trie() {for (int i = 0; i < trie.size(); i++) {cout << trie[i].c << "|";for (int j = 0; j < 30; j++) {if (trie[i].children[j])cout << trie[i].children[j] << " ";}cout << "|" << trie[i].end << "|" << trie[i].repeat<<endl;}
}

应用

  • P2580 于是他错误的点名开始了:标准的查询字符串操作。

0-1字典树

  • 将数字用二进制形式保存在trie中,一般是高位到低位。配合贪心思想,可以节约查询操作

  • P4551 最长异或路径:这里需要用的异或的自反性质:自己跟自己异或不影响计算。当i<j, [ 1 , i ] ⊕ [ 1 , j ] = [ i , j ] [1,i] \oplus [1,j]=[i,j] [1,i][1,j]=[i,j], [ i , j ] [i,j] [i,j]表示i到j的异或路径。现在这个问题就变成了先获得[1,i],然后再遍历每个j,计算 [ 1 , i ] ⊕ [ 1 , j ] [1,i] \oplus [1,j] [1,i][1,j]的最大值。时间复杂度为平方。将这些[1,i]结果保存为字典树,然后利用贪心从高位到低位选择最大的异或结果即可

  • 注意bitset<int>val这个库,接受字符串和整型作为构造函数。一定要注意的是遍历时:从低位到高位遍历,val[0]表示从右往左第一位(也就是低位)for (int i = bitval.size() - 1; i >= 0; i--)

#include<bits/stdc++.h>
#define MAX_VALUE 1000009
#define mod 1000007
using ll = long long;
using namespace std;
typedef struct node {int x, w;node(int a, int b) :x(a), w(b) {};
};
typedef struct trie_node {int val, children[2] = { 0 };
};
vector<list<node>>graph(100009, list<node>());
int n, u, v, w, xors[100009], ans = INT_MIN;
vector<trie_node>trie;
void dfs(int st, int val) {xors[st] = val;for (auto item : graph[st]) {dfs(item.x, val ^ item.w);}
}
void build(int val) {int fa = 0;bitset<32>bitval(val);//bitset[0]是指第一位for (int i = bitval.size() - 1; i >= 0; i--) {//cout << "val:"<<val<<" i:"<<i<<" bitval[i]:" << bitval[i] << endl;if (!trie[fa].children[bitval[i]]) {int new_idx = trie.size();trie[fa].children[bitval[i]] = new_idx;trie_node x;x.val = bitval[i];trie.push_back(x);fa = new_idx;}else {fa = trie[fa].children[bitval[i]];}}
}
int query(int val) {int fa = 0;bitset<32>bitval(val);//二进制bitset<32>res;//bitset[0]是指第一位for (int i = bitval.size() - 1; i >= 0; i--) {if (trie[fa].children[!bitval[i]]) {//取反fa = trie[fa].children[!bitval[i]];res[i] = 1;}else {fa = trie[fa].children[bitval[i]];res[i] = 0;}}return (int)res.to_ulong();
}
void printout() {for (int i = 0; i < trie.size(); i++) {cout << trie[i].val << "|";for (int j = 0; j < 2; j++) {if (trie[i].children[j])cout << trie[i].children[j] << " ";}cout << "|" << endl;}
}
void solve() {cin >> n;for (int i = 1; i < n; i++) {cin >> u >> v >> w;graph[u].push_back(node(v, w));}dfs(1, 0);//for (int i = 1; i <= n; i++) {//	cout << xors[i] << " ";//}//cout << endl;trie_node root;trie.push_back(root);for (int i = 1; i <= n; i++) {build(xors[i]);}//printout();for (int i = 1; i <= n; i++) {ans = max(ans, query(xors[i]));}cout << ans;}
int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);solve();return 0;
}
  • P6824 「EZEC-4」可乐:这里x是有最大值的,暴力方法是对于每一个x都进行异或看看是否满足条件,时间复杂度为平方。利用a[i]构造0-1trie,可以在位级别,加速判断。对于第i位,如果k[i]为1,只需要找到与x[i]相同数字的结点,就一定可以知道x与该结点下的a[i]满足条件。如果k[i]=0,需要找到与x[i]相同数字的结点,否则一定不能与该父节点下的a[i]满足条件,提前结束。这里也是用由高位到低位的贪心思想
#include<bits/stdc++.h>
#define MAX_VALUE 1000009
#define mod 1000007
using ll = long long;
using namespace std;
int n, k, a[1000009],res=INT_MIN;
typedef struct node {int val, children[2] = {0}, repeat = 1;
};
vector<node>trie;
void build(int val) {bitset<32>bitval(val);int fa = 0;for (int i = bitval.size() - 1; i >= 0; i--) {if (!trie[fa].children[bitval[i]]) {int new_idx = trie.size();trie[fa].children[bitval[i]] = new_idx;node x;x.val = bitval[i];trie.push_back(x);fa = new_idx;}else {int idx = trie[fa].children[bitval[i]];fa = idx;trie[idx].repeat++;}}
}
void printout() {for (int i = 0; i < trie.size(); i++) {cout << trie[i].val << "|";for (int j = 0; j < 2; j++) {if(trie[i].children[j])cout << trie[i].children[j] << " ";}cout << "|" << trie[i].repeat << endl;}
}
int query(int val,int k) {int ans = 0;bitset<32>bitval(val);bitset<32>bitk(k);int fa = 0;for (int i = bitval.size() - 1; i >= 0; i--) {if (bitk[i]) {//bitk[i]==1if (trie[fa].children[bitval[i]]) {//xor can be 0int idx = trie[fa].children[bitval[i]];//cout << bitval[i] << " "<<trie[idx].repeat << endl;ans += trie[idx].repeat;}if (trie[fa].children[!bitval[i]]) {fa = trie[fa].children[!bitval[i]];}else {break;}}else {//bitk[i]==0if (trie[fa].children[bitval[i]]) {fa = trie[fa].children[bitval[i]];if (i == 0) {ans += 1;//最后一个结点//cout << "end:" << 1 << endl;}}else break;}}return ans;
}
void solve() {node root;trie.push_back(root);cin >> n >> k;for (int i = 1; i <= n; i++) {cin >> a[i];build(a[i]);}//printout();for (int i = 0; i <= (1<<20); i++) {res = max(res, query(i, k));}cout << res;//cout<<query(0, k);
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);solve();return 0;
}

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

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

相关文章

ES面试题系列「一」

1、Elasticsearch 是什么&#xff1f;它与传统数据库有什么区别&#xff1f; 答案&#xff1a;Elasticsearch 是一个基于 Lucene 的分布式、开源的搜索和分析引擎&#xff0c;主要用于处理大量的文本数据&#xff0c;提供快速的搜索和分析功能。与传统数据库相比&#xff0c;E…

2025年6月一区SCI-不实野燕麦优化算法Animated Oat Optimization-附Matlab免费代码

引言 近年来&#xff0c;在合理框架内求解优化问题的元启发式算法的发展引起了全球科学界的极大关注。本期介绍一种新的元启发式算法——不实野燕麦优化算法Animated Oat Optimization algorithm&#xff0c;AOO。该算法模拟了不实野燕麦的3种独特行为&#xff0c;于2025年6月…

Agent Builder API - Agent Smith 扩展的后端服务(开源代码)

​一、软件介绍 文末提供程序和源码下载 Agent Builder API - Agent Smith 扩展的后端服务&#xff08;开源代码&#xff09;手动设置&#xff1a;在本地计算机中克隆此存储库并启动 python FAST API 服务器。&#xff08;可选&#xff09;安装并设置 Mongo DB。Dev Container…

C及C++的SOAP协议库

一.gSOAP gSOAP 是一个功能强大的开源工具包&#xff0c;专为 C 和 C 设计&#xff0c;用于快速开发基于 SOAP 协议的 Web 服务和客户端。 1.协议支持 SOAP 版本&#xff1a;完整支持 SOAP 1.1/1.2 规范&#xff0c;包括消息格式、编码规则和错误处理。 传输协议&#xff1a…

html5+css3实现傅里叶变换的动态展示效果(仅供参考)

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>傅里叶变换的动态展示效果</title><sty…

ECharts中Map(地图)样式配置、渐变色生成

前言 在日常开发中&#xff0c;ECharts 几乎成了我们绘制数据图表的标配工具&#xff0c;功能强大到几乎无所不能。不过每次用的时候都要翻官方文档查配置项&#xff0c;确实有点小繁琐 &#x1f605; 为了提升效率&#xff0c;也方便以后快速复用&#xff0c;这里就整理记录…

内存分配器ptmalloc2、tcmalloc、jemalloc,结构设计、内存分配过程详解

1. 引言 博主之前做过一个高并发内存池的项目实践&#xff0c;在实践中对于内存分配器的内存分配过程理解更加深刻了。在此期间&#xff0c;翻查了不少资料以及博客&#xff0c;发现源码分享的博客不多&#xff0c;能生动完整的讲述ptmalloc2、tcmalloc、jemalloc它们的结构设…

【拥抱AI】Deer-Flow字节跳动开源的多智能体深度研究框架

最近发现一款可以对标甚至可能超越GPT-Researcher的AI深度研究应用&#xff0c;Deer-Flow&#xff08;Deep Exploration and Efficient Research Flow&#xff09;作为字节跳动近期开源的重量级项目&#xff0c;正以其模块化、灵活性和人机协同能力引发广泛关注。该项目基于 La…

openfeign与dubbo调用下载excel实践

一、前言 openfeign和dubbo均是rpc框架 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;框架 是一种允许程序像调用本地方法一样调用远程服务器上函数的技术。它隐藏了底层网络通信的复杂性&#xff0c;让开发者可以专注于业务逻辑&#xff0c;实现…

解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs-强化学习算法

解密企业级大模型智能体Agentic AI 关键技术&#xff1a;MCP、A2A、Reasoning LLMs-强化学习算法 现在我们的核心问题是有一些同学会知道要才能强化学习。为什么才能强化学习&#xff1f;是实现AGI。例如从这个其实你从第一阶段开始以后&#xff0c;就是chatbot&#xff0c;这…

音频分类的学习

1.深度学习PyTorch入门-语音分类 https://blog.csdn.net/sinat_41787040/article/details/129795496 https://github.com/musikalkemist/pytorchforaudio https://github1s.com/musikalkemist/pytorchforaudio/blob/main/04%20Creating%20a%20custom%20dataset/urbansoundda…

美SEC主席:探索比特币上市证券交易所

作者/演讲者&#xff1a;美SEC主席Paul S. Atkins 编译&#xff1a;Liam 5月12日&#xff0c;由美国SEC加密货币特别工作组发起的主题为《资产上链&#xff1a;TradFi与DeFi的交汇点》系列圆桌会议如期举行。 会议期间&#xff0c;现任美SEC主席Paul S. Atkins发表了主旨演讲。…

Qt file文件操作详解

1.引言 很多应用程序都具备操作文件的能力&#xff0c;包括对文件进行写入和读取&#xff0c;创建和删除文件等等&#xff0c;甚至某些应用程序的就是为了操作文件&#xff0c;像WPS Office。基于此Qt框架中专门提供了对文件操作的类&#xff1a;QFile。 2.QFile文件操作 QF…

【测试开发知识储备】之Jacoco(Java Code Coverage)

文章目录 Jacoco是什么Jacoco的主要功能&#xff08;一&#xff09;多样化覆盖率指标分析&#xff08;二&#xff09; 丰富的报告生成&#xff08;三&#xff09;实时数据收集 Jacoco的工作原理&#xff08;一&#xff09;字节码增强&#xff08;二&#xff09;测试执行与数据收…

Docker 介绍与使用

Docker 文章目录 Docker介绍与虚拟机的比较启动速度占用资源 优势更容易迁移更容易维护更容易扩展 使用场景持续集成提供可伸缩的云服务搭建微服务架构 镜像与容器镜像构成&#xff08;分层结构&#xff09;镜像与容器的区别 安装 Docker常用命令介绍镜像相关容器相关 实战&…

《AI大模型应知应会100篇》第62篇:TypeChat——类型安全的大模型编程框架

第62篇&#xff1a;TypeChat——类型安全的大模型编程框架 摘要 在构建 AI 应用时&#xff0c;一个常见的痛点是大语言模型&#xff08;LLM&#xff09;输出的不确定性与格式不一致问题。开发者往往需要手动解析、校验和处理模型返回的内容&#xff0c;这不仅增加了开发成本&a…

upload-labs通关笔记-第5关 文件上传之.ini绕过

目录 一、ini文件绕过原理 二、源码审计 三、渗透实战 1、查看提示 2、制作.user.ini文件 &#xff08;1&#xff09;首先创建一个文本文件 &#xff08;2&#xff09;保存文件名为.user.ini 2、制作jpg后缀脚本 &#xff08;1&#xff09;创建一个文本文件 &#xf…

为什么 Linux 上默认没有 host.docker.internal

在 Linux 环境中&#xff0c;host.docker.internal 是 Docker 为容器提供的一个特殊 DNS 名称&#xff0c;用于指向宿主机的 IP 地址&#xff08;类似 macOS/Windows 中的行为&#xff09;。但这个功能在 Linux 上默认不启用&#xff0c;需要手动配置才能使用。以下是详细解释和…

C++GO语言微服务和服务发现②

01 创建go-micro项目-查看生成的 proto文件 02 创建go-micro项目-查看生成的main文件和handler ## 创建 micro 服务 命令&#xff1a;micro new --type srv test66 框架默认自带服务发现&#xff1a;mdns。 使用consul服务发现&#xff1a; 1. 初始consul服务发现&…

Redis--常见数据类型List列表

目录 一、概念 二、命令 2.1 LPUSH 2.2 LPUSHX 2.3 RPUSH 2.4 RPUSHX 2.5 LRANGE 2.6 LPOP 2.7 RPOP 2.8 LINDEX 2.9 LINSERT 2.10 LLEN 2.11 阻塞版本命令 三、内部编码 一、概念 列表类型是用来存储多个有序的字符串&#xff0c;列表中的每个字符串称为元素&…