trie 树

article/2025/9/22 1:11:42

一、普通 t r i e \rm trie trie

t r i e \rm trie trie 树又称字典树、前缀树,它把很多单词放到一棵树上,使用空间去换时间。

LUOGU2580 于是他错误的点名开始了

Description \text{Description} Description

给定 n n n 个互不相同且只含小写字母的字符串,以及 m m m 个问题,每个问题给出一个字符串 S S S

  1. S S S 在这 n n n 个字符串中出现过:

    1. S S S 是第一次被问,输出OK
    2. S S S 已经被问过,输出REPEAT
  2. S S S 在这 n n n 个字符串中未出现过,输出WRONG

Solution \text{Solution} Solution

我们设 t r i e p , c trie_{p,c} triep,c 来表示 t r i e trie trie p p p 的儿子中第 c c c 个所对应的节点,其中 c c c 可取 1 ∼ 26 1\sim26 126,分别代表 a ∼ z \text{a}\sim\text{z} az

1. 插入

当我们要插入字符串 S S S 的时候,遍历整个 S S S,同时用一个 p o s pos pos 记录当前访问到的节点, p o s pos pos 一开始指向根节点,即 p o s = 0 pos=0 pos=0,当现在遍历到第 i i i 位时,令 c = S[i] - 'a'

  1. t r i e p o s , c = 0 trie_{pos,c}=0 triepos,c=0,说明这个位置还没有节点,那就新建一个;
  2. p o s = t r i e p o s , c pos=trie_{pos,c} pos=triepos,c
int tot;
int trie[MAXN][26]; //MAXN为所有字符串的总长度void insert(char *s)
{int len = strlen(s), pos = 0;for (int i = 0; i < len; i++){int c = s[i] - 'a';if (!trie[pos][c]){trie[pos][c] = ++tot; //新建节点}pos = trie[pos][c];}
}

例如现在要插入单词 at,sea,see,meat \text{at,sea,see,meat} at,sea,see,meat

首先插入 at \text{at} at
然后是 sea \text{sea} sea
插入 see \text{see} see 时, t r i e \rm trie trie 上已有前缀 se \text{se} se,所以变成了这样:
最后是 meat \text{meat} meat

2. 查询

和插入差不多。

  1. t r i e p o s , c = 0 trie_{pos,c}=0 triepos,c=0 时,说明 S S S 不在 t r i e \rm trie trie 中;
  2. 若遍历完整个字符串,说明 S S S t r i e \rm trie trie 中。

对于本题,我们用一个 v i s vis vis 数组来记录 S S S 是否是第一次被询问。

int search(char *s)
{int len = strlen(s), pos = 0;for (int i = 0; i < len; i++){int c = s[i] - 'a';if (!trie[pos][c]){return 0; //WRONG}pos = trie[pos][c];}if (vis[pos]){return 2; //REPEAT}vis[pos] = true;return 1; //OK
}

t r i e \rm trie trie 树的插入,查询时间复杂度均为 O ( l e n ) \mathcal{O}(len) O(len)。空间复杂度为 O ( ∑ l e n × 26 ) \mathcal{O}(\sum len\times26) O(len×26),这是典型的空间换时间。

Code \text{Code} Code

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;const int MAXN = 5e5 + 5;int tot;
int trie[MAXN][26];
bool vis[MAXN];void insert(char *s)
{int len = strlen(s), pos = 0;for (int i = 0; i < len; i++){int c = s[i] - 'a';if (!trie[pos][c]){trie[pos][c] = ++tot;}pos = trie[pos][c];}
}int search(char *s)
{int len = strlen(s), pos = 0;for (int i = 0; i < len; i++){int c = s[i] - 'a';if (!trie[pos][c]){return 0;}pos = trie[pos][c];}if (vis[pos]){return 2;}vis[pos] = true;return 1;
}char s[55];int main()
{int n, m;scanf("%d", &n);while (n--){scanf("%s", s);insert(s);}scanf("%d", &m);while (m--){scanf("%s", s);int res = search(s);if (!res){puts("WRONG");}else if (res == 1){puts("OK");}else{puts("REPEAT");}}return 0;
}

二、 01 \rm 01 01- t r i e \rm trie trie

01 \rm 01 01- t r i e \rm trie trie 是一种 很 大 聪 明 的 \color{White}{很大聪明的} t r i e \rm trie trie 的变形,它的树上只有 0 0 0 1 1 1

LOJ#10050. 「一本通 2.3 例 2」The XOR Largest Pair

Description \text{Description} Description

给定 N N N 个整数,从中选出两个进行异或运算,问得到的结果最大是多少。

Solution \text{Solution} Solution

考虑贪心。在二进制下,一个数的第 i i i 位为 0 0 0,那我们就尽量给他找个 1 1 1,反之就找个 0 0 0,这样就能使异或后的数有尽量多的位为 1 1 1

那么可以把所有的数转成二进制后扔到 t r i e \rm trie trie 上,这样 t r i e \rm trie trie 上就只有 0 0 0 1 1 1,这就是 01 \rm 01 01- t r i e \rm trie trie

但是实际上并不需要先转成二进制,我们可以在 insert ⁡ \operatorname{insert} insert 的时候顺带处理。

void insert(int val)
{int pos = 0;for (int i = 30; i >= 0; i--){int c = (val >> i) & 1; //取出第i位if (!trie[pos][c]){trie[pos][c] = ++tot;}pos = trie[pos][c];}
}

然后 search ⁡ \operatorname{search} search 的时候就按照上面的贪心去找,如果实在没有那就只能取相同的了。

int search(int val)
{int pos = 0, res = 0;for (int i = 30; i >= 0; i--){int c = (val >> i) & 1;if (trie[pos][c ^ 1]) //如果有就取{res |= (1 << i);pos = trie[pos][c ^ 1];}else{pos = trie[pos][c];}}return res;
}

Code \text{Code} Code

#include <iostream>
#include <cstdio>
using namespace std;const int MAXN = 1e5 + 5;int tot;
int trie[MAXN * 32][2];void insert(int val)
{int pos = 0;for (int i = 30; i >= 0; i--){int c = (val >> i) & 1;if (!trie[pos][c]){trie[pos][c] = ++tot;}pos = trie[pos][c];}
}int search(int val)
{int pos = 0, res = 0;for (int i = 30; i >= 0; i--){int c = (val >> i) & 1;if (trie[pos][c ^ 1]){res |= (1 << i);pos = trie[pos][c ^ 1];}else{pos = trie[pos][c];}}return res;
}int a[MAXN];int main()
{int n, ans = 0;scanf("%d", &n);for (int i = 1; i <= n; i++){scanf("%d", a + i);ans = max(ans, search(a[i]));insert(a[i]);}printf("%d\n", ans);return 0;
}

LOJ#10056. 「一本通 2.3 练习 5」The XOR-longest Path

Descripton \text{Descripton} Descripton

给定一棵 n n n 个点的带权树,求树上最长的异或和路径。

Solution \text{Solution} Solution

预处理出 d e p dep dep 数组, d e p i dep_i depi 表示节点 i i i 到根节点的路径上所有边的边权的异或和。

比如我们要求节点 x x x 到节点 y y y 路径上所有边的边权和,设 LCA ⁡ ( x , y ) = z \operatorname{LCA}(x,y)=z LCA(x,y)=z,那么 d e p x ⊕ d e p y dep_x\oplus dep_y depxdepy 多算了 2 2 2 d e p z dep_z depz,根据异或的运算律,这 2 2 2 d e p z dep_z depz 异或在一起会抵消,所以 d e p x ⊕ d e p y dep_x\oplus dep_y depxdepy 就等于 x x x y y y 路径上的边的边权异或和。

所以预处理出 d e p dep dep 数组然后就变成了上面那题(((

Code \text{Code} Code

#include <iostream>
#include <cstdio>
using namespace std;const int MAXN = 1e5 + 5;int tot;
int trie[MAXN * 100][2];void insert(int val)
{int pos = 0;for (int i = 30; i >= 0; i--){int c = (val >> i) & 1;if (!trie[pos][c]){trie[pos][c] = ++tot;}pos = trie[pos][c];}
}int search(int val)
{int pos = 0, res = 0;for (int i = 30; i >= 0; i--){int c = (val >> i) & 1;if (trie[pos][c ^ 1]){res |= (1 << i);pos = trie[pos][c ^ 1];}else{pos = trie[pos][c];}}return res;
}int cnt;
int head[MAXN], dep[MAXN];struct edge
{int to, dis, nxt;
}e[MAXN << 1];void add(int u, int v, int w)
{e[++cnt] = edge{v, w, head[u]};head[u] = cnt;
}void dfs(int u, int fa)
{for (int i = head[u]; i; i = e[i].nxt){int v = e[i].to;if (v == fa){continue;}dep[v] = dep[u] ^ e[i].dis;dfs(v, u);}
}int main()
{int n, ans;scanf("%d", &n);for (int i = 1; i < n; i++){int u, v, w;scanf("%d%d%d", &u, &v, &w);add(u, v, w);add(v, u, w);}dfs(1, 0);for (int i = 1; i <= n; i++){insert(dep[i]);ans = max(ans, search(dep[i]));}printf("%d\n", ans);return 0;
}

http://chatgpt.dhexx.cn/article/FqppPuAq.shtml

相关文章

Trie

文章目录 应用替换其他数据结构字典表达术语索引 算法排序全文检索 实现Bitwise triesCompressing triesExternal memory trie About Me Trie ,也叫做 digital tree(数字树) 有时候也是 radix tree(基数树) 或者 prefix tree(前缀树) (因为他们可以通过前缀进行搜索) 是一种 se…

Trie(字典树/前缀树)

字典树/前缀树 Trie&#xff08;发音类似 “try”&#xff09;或者说 前缀树&#xff08;字典树&#xff09; 是一种树形数据结构&#xff0c;用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景&#xff0c;例如自动补完和拼写检查。主要思想是利用字符…

trie(字典树、前缀树)

trie&#xff08;字典树、前缀树&#xff09; 1. trie原理 原理 trie树&#xff0c;又被称为字典树、前缀树&#xff0c;是一种高效地存储和查找字符串集合的数据结构。一般来说&#xff0c;用到trie的题目中的字母要么全是小写字母&#xff0c;要么全是大写字母&#xff0c;要…

Trie详解

Trie&#xff0c;又名字典树、单词查找树&#xff0c;可以较高效地实现统计、排序和保存大量的字符串。 顾名思义&#xff0c;Trie是一个树状的结构&#xff0c;按照树型结构来存储字符串&#xff0c;显然是一种以空间换时间的方法。整体上理解和实现都不会很难。 下面是实现方…

Trie 简介

一、Trie简介 在计算机科学中&#xff0c;Trie&#xff0c;又称字典树、前缀树、单词查找树或键树&#xff0c;是一种树形结构&#xff0c;是一种哈希树的变种。典型应用是用于统计&#xff0c;排序和保存大量的字符串&#xff08;但不仅限于字符串&#xff09;&#xff0c;所以…

Trie 字典树 详解

&#x1f60a; | Powered By HeartFireY | Tire Algorithm 一、字典树 1.字典树简介 字典树&#xff0c;英文名Trie&#xff0c;如其名&#xff1a;就是一棵像字典一样的树。 我们首先通过一张图来理解字典树的结构&#xff1a; 我们假定结点的顺序按照图中给定的顺序进行编…

Web前端面试题汇总(持续更新...)

H5 的新特性有哪些&#xff1f;C3 的新特性有哪些&#xff1f; H5 新特性 拖拽释放(Drap and drop) API ondrop自定义属性 data-id语义化更好的内容标签(header,nav,footer ,aside, article, section)音频 ,视频(audio, video) 如果浏览器不支持自动播放怎么办?在属性中添加…

Web前端面试题(全锦集)

1 第一部分&#xff1a; 聪明的猴子都在看右下角目录 点击查看更多资源 前端基础(HTML CSS JS基础) 1. 怎么让一个不定宽高的 DIV&#xff0c;垂直水平居中&#xff1f; 答&#xff1a;1.使用 CSS 方法&#xff1a; 父盒子设置&#xff1a;display&#xff1a;table…

web前端开发面试题(一)

一、html部分 1.1 link和import 区别如下&#xff1a; 1.1.1从属关系区别 import是 CSS 提供的语法规则&#xff0c;只有导入样式表的作用&#xff1b;link是HTML提供的标签&#xff0c;不仅可以加载 CSS 文件&#xff0c;还可以定义 RSS、rel 连接属性等。 2.加载顺序区别…

Web常见前端面试题及答案

前端技术导航大全 1、盒子模型 盒子模型包括四部分&#xff1a;内容&#xff08;content&#xff09;、填充&#xff08;padding&#xff09;、边框&#xff08;border&#xff09;、边界&#xff08;margin&#xff09; 盒子模型可以分为两种&#xff1a;IE盒子模型和W3C标准…

web前端开发面试题(七)

前端面试题第七天 一、HTML 部分 1.1 iframe框架都有哪些优缺点 在讲iframe框架之前 先聊聊iframe吧 定义&#xff1a;iframe是HTML标签&#xff0c;作用是文档中的文档&#xff0c;或者浮动的框架(FRAME)。iframe元素会创建包含另外一个文档的内联框架&#xff08;即行内框…

2020 web前端面试题及答案大全

css相关 1. 万能居中 1.margin: 0 auto;水平 2.text-align: center;水平 3.行高&#xff0c;垂直 4.表格&#xff0c;center,middle&#xff1b;水平垂直 5.display:table-cell&#xff1b;模拟表格&#xff0c;all 6.绝对定位&#xff0c;50%减自身宽高 7.绝对定位&#xff…

初级web前端面试题

文章目录 一、JS1、js基本类型和引用类型2、如何判断js数据类型3、js 拷贝4、事件处理机制5、原型和原型链6、什么是闭包7、事件循环机制&#xff08;event loop&#xff09;8、前端模块化9、es6新增特性1.let代替var关键字&#xff1b;2.const3.箭头函数4.字符串模板 &#xf…

【面试】web前端经典面试题试题及答案(持续更新)-html/css

html/ css css盒模型、BFC、css浮动、css经典布局、css兼容、css hack、html/ css基础 css盒模型BFCcss浮动css经典布局自适应css兼容css hackhtml/ css基础css3 transformcss实战图片 #mermaid-svg-vRGce0x6PUoXllsG .label{font-family:trebuchet ms, verdana, arial;font-fa…

前端面试题2021及答案

身为三本的我就是凭借这些前端面试题拿到百度京东offer的&#xff0c;前端面试题2021及答案... 此文转载自&#xff1a;https://blog.csdn.net/qq_33277654/article/details/112758362#commentBox 点进来之后你的噩梦就要来了&#xff0c;接下来你要面对上百道面试题&#xff…

web前端面试题(全)

近来看到网上格式各样的web前端求职的面试题&#xff0c;接下来我用我的经验总结了一套在面试过程中高频率问到的面试题&#xff0c;希望能帮助各位求职者在求职的过程中顺利通过&#xff0c;废话不多说&#xff0c;直接说题。。。 一、HTML5部分 1.说一下对css盒模型的理解 …

2023最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)

近期总结一一些面试题 都是企业的面试题笔记题 感觉薪资10k-15k的常见面试题 个人录制的最新Vue项目学习视频&#xff1a;B站 Vue2-第二版-后台管理系统项目实战/vueelement-ui/vue经典全套系统案例讲解_哔哩哔哩_bilibili 前端面试题视频讲解&#xff1a; 2023前端高频…

Web前端面试:这40个经典Web前端面试题面试者必看!

想成功就业Web前端工程师&#xff0c;想要能高薪就业&#xff0c;那么除了好的Web前端技能以外&#xff0c;还得有好的面试技巧&#xff0c;如果提前就了解更多企业的面试要求及面试题目&#xff0c;那么可以让我们的面试成功的几率大大的提高。今天千锋武汉Web前端培训小编为大…

最新Web前端面试题精选大全及答案

目录 HTML、CSS相关 Javascript相关 三者的异同 Vue相关 55.Vue路由懒加载&#xff08;按需加载路由&#xff09; React相关 react 生命周期函数 ******为什么虚拟 dom 会提高性能?(必考) (组件的)状态(state)和属性(props)之间有何不同 shouldComponentUpdate 是做…

50道web前端工程师面试题及答案解析,你学会了吗

简介&#xff1a;本文包含了50个实用的前端面试题及答案解析&#xff0c;涵盖了HTML、CSS、JavaScript、DOM、Ajax、MVC、模块化、ES6、SPA、Webpack、Babel、Virtual DOM、响应式设计、移动优先设计、响应式图片、CSS 预处理器、后处理器、模块化、布局、盒模型、浮动、定位、…