Tire树 学习笔记
定义与基本求法
定义
又称字典树,用边表示字母,从根节点到树上某一节点路径形成一个字符串。
例如 \(charlie:\)

基本求法
廷显然的,往树中存就行了,查询也是显然的,通过一道例题来理解吧:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=5e5+10,P=1e9+7;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
char s[N];
int n,m,t[N][30],v[N],tot=1;
void Tire(char s[])
{
int r=1,l=strlen(s+1);
for(int i=1;i<=l;i++)
{
int c=s[i]-'a';
if(!t[r][c]) t[r][c]=++tot;
r=t[r][c];
}
v[r]=1;
}
void ask(char s[])
{
int r=1,l=strlen(s+1);
for(int i=1;i<=l;i++)
{
int c=s[i]-'a';
r=t[r][c];
if(!r) break;
}
if(v[r]==1)
{
cout<<"OK"<<endl;
v[r]=2;
}
else if(v[r]==2)
cout<<"REPEAT"<<endl;
else cout<<"WRONG"<<endl;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n);
for(int i=1;i<=n;i++)
cin>>s+1,
Tire(s);
read(m);
for(int i=1;i<=m;i++)
cin>>s+1,
ask(s);
}
\(t\) 数组存的现节点是编号,第一维存的是根节点编号,第二维是边权。
查询时,遇到该字符对应编号为 \(0\) ,说明这个字符串不存在与字典树中。
例题
题面:
给定 \(n\) 个字符串,判断是否存在两个字符串 \(s,t\) ,使 \(s\) 是 \(t\) 的前缀。
解法:
多测,\(n^2\) 匹配—— \(Hash×\)
将每一组存到字典树中,同时查询是否有前缀等于之前的串即可。
可以定义一个新的数组 \(f_p\) 用于判断,判断字符串 \(s\) 时,只要出现 \(f_p=1\) 就说明有字符串与其匹配了,当然,存的时候,存完另 \(f_p=1\) 。
结合代码理解。
代码如下:
#include<bits/stdc++.h>
#define int unsigned long long
#define endl '\n'
using namespace std;
const int N=1e6+10,P=1e9+7;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
int T,n,t[N][20],tot=1;
char s[N];
bool f[N];
void Tire(char s[])
{
int p=1,l=strlen(s+1);
for(int i=1;i<=l;i++)
{
int c=s[i]-'0';
if(!t[p][c]) t[p][c]=++tot;
p=t[p][c];
}
f[p]=1;
}
bool find(char s[])
{
int p=1,l=strlen(s+1);
for(int i=1;i<=l;i++)
{
int c=s[i]-'0';
if(!t[p][c]) return 0;
p=t[p][c];
if(f[p]) return 1;
}
return 1;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(T);
while(T--)
{
memset(f,0,sizeof(f));
memset(t,0,sizeof(t));
tot=1;
bool ans=0;
read(n);
for(int i=1;i<=n;i++)
{
cin>>s+1;
if(find(s)) ans=1;
Tire(s);
}
if(!ans) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
\(01Tire\)
定义与基本求法:
定义
字符集只有 \(0||1\) 的 \(Tire\) 数,主要用来解决有关异或值的问题。
基本求法:
异或有着安慰考虑的性质,每一位贡献是分开的,这与 \(Tire\) 树用不同深度存不同位定性质是吻合的。
如果要最大化异或值,一定先最大化其最高位,如果用 \(Tire\) 树从高到低来做,正好吻合了这个贪心思想。
根据例题来理解吧。
例题
\(The XOR Largest Pair\)
题面:
给定 \(n\) 个整数 \(a_i\sim a_n\) ,在其中选出两个进行异或运算,求可以得到的最大结果。
解法:
\(n\) 足够大,暴力不要想。
将这 \(n\) 个数转换成二进制,存到 \(Tire\) 树里。
再取这 \(n\) 个树,在 \(Tire\) 上跑一边,尽可能的向与其二进制位不同的方向。
此处体现了贪心的思想,因为二进制下 \(1aaaa>0bbbb\) 始终成立,高位优一定全局优。
代码如下:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=3e6+10,P=1e9+7;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
int n,a[N],tot,t[N][2],ans;
void Tire(int x)
{
int p=0;
for(int i=31;i>=0;i--)
{
int l=(x>>i)&1;
if(!t[p][l]) t[p][l]=++tot;
p=t[p][l];
}
}
int find(int x)
{
int p=0,sum=0;
for(int i=31;i>=0;i--)
{
int l=(x>>i)&1;
if(t[p][l^1])
p=t[p][l^1],
sum=sum<<1|1;//二进制运算
else
p=t[p][l],sum=sum<<1;//同上
}
return sum;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n);
for(int i=1;i<=n;i++)
read(a[i]),
Tire(a[i]);
for(int i=1;i<=n;i++)
ans=max(ans,find(a[i]));
cout<<ans;
}
位运算方向注意不要写反了。
\(The XOR-longest Path\)
题面:
给定一棵 \(n\) 个节点的带权树,求书上最长的异或和路径。
解法:
首先了解异或的一个重要性质——自反性:
\(x\oplus x=0\)
所以一个元素,若对其进行了重复偶数次的重复,则视作没有异或。
∴ \(path(x,y)=path(x,lca)\oplus path(lca,y)=path(x,root)\oplus path(root,y)\)
故此求出每个点到根节点的异或和 \(d_i\) ,将 \(d_i\) 存到 \(Tire\) 中,问题就转化为了上一道题。
至于如何求每个节点到根节点的异或和,可以用 \(dfs\) 解决。
总结
对于 \(Tire\) 树此处涉及并不多,也还没有讲,上网上自己找的。
直接使用 \(Tire\) 树的问题还是相对容易的,也很好理解,\(01Tire\) 也是直接使用 \(Tire\) 的一个应用了,虽然只能解决异或问题。
而此处对其进行整理主要为了为后面的 \(AC\) 自动机等知识点做准备。
由此看,\(Tire\) 树还是很重要的,要牢牢掌握。
Tire树 学习笔记的更多相关文章
- zkw线段树学习笔记
zkw线段树学习笔记 今天模拟赛线段树被卡常了,由于我自带常数 \(buff\),所以学了下zkw线段树. 平常的线段树无论是修改还是查询,都是从根开始递归找到区间的,而zkw线段树直接从叶子结点开始 ...
- 仙人掌&圆方树学习笔记
仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...
- 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解
什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...
- Treap-平衡树学习笔记
平衡树-Treap学习笔记 最近刚学了Treap 发现这种数据结构真的是--妙啊妙啊~~ 咳咳.... 所以发一发博客,也是为了加深蒟蒻自己的理解 顺便帮助一下各位小伙伴们 切入正题 Treap的结构 ...
- JSOI2008 Blue Mary开公司 | 李超线段树学习笔记
题目链接:戳我 这相当于是一个李超线段树的模板qwqwq,题解就不多说了. 代码如下: #include<iostream> #include<cstdio> #include ...
- Splay伸展树学习笔记
Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...
- CART分类与回归树 学习笔记
CART:Classification and regression tree,分类与回归树.(是二叉树) CART是决策树的一种,主要由特征选择,树的生成和剪枝三部分组成.它主要用来处理分类和回归问 ...
- B和B+树学习笔记
二叉树 如果数据都在内存中,我们就用平衡二叉查找树即可,这样效率最高. 在前面的文章中我使用过红黑树(大致平衡的二叉查找树),500万节点时,搜索的深度可以达到50,也就是需要50次指针操作才能获取到 ...
- Trie树 字典树-学习笔记
字符串--蒟蒻永远的阴影 对于字符串匹配 KMP很好的解决了以一个文本串匹配一个模板串的问题 但如果模板串有多个呢 这是KMP不再适用 我们引入一个新的数据结构--字典树 (当然又有像AC自动机这样更 ...
- 一篇自己都看不懂的点分治&点分树学习笔记
淀粉质点分治可真是个好东西 Part A.点分治 众所周知,树上分治算法有$3$种:点分治.边分治.链分治(最后一个似乎就是树链剖分),它们名字的不同是由于分治方式的不同的.点分治,顾名思义,每一次选 ...
随机推荐
- UVA - 1594 :Ducci Sequence (set应用)
给定n元组(a1,a2,...,an),ai均为整数,得到下一个序列为(|a1-a2|,|a2-a3|,...,|an-a1|),如此循环下去,必定会出现全零序列或重复序列. 现要求判断给定序列是全零 ...
- Codeforces 670C (离散化入门题)
原题链接:https://codeforces.com/problemset/problem/670/C 题目大意: 有 n 个人,每人会且仅会一种语言. (n ≤ 2e5) 语言有各自的编号(≤ 1 ...
- 【每日一题】32. 比赛 (DFS / 概率DP)
补题链接:Here [方案一:DFS] 首先我们可以计算出每道题做不出来的概率 \(unsolve[i] = (1 - a[i])(1- b[i])(1 - c[i])\) 然后因为只有 12 道题, ...
- springboot项目统一封装返回值和异常处理(方式一)
为什么要统一返回值: 在我们做后端应用的时候,前后端分离的情况下,我们经常会定义一个数据格式,通常会包含code,message,data这三个必不可少的信息来方便我们的交流,下面我们直接来看代码pa ...
- maven总结一: 常用命令
本文为博主原创,未经允许不得转载: maven常用命令: 1. mvn clean maven清理 2. mvn compile maven 编译 3. mvn package maven 打包 ...
- @Async异步操作及异步线程池
本文为博主原创,转载请注明出处: @Async 用来实现异步请求操作,使用@Async 注解时,需要同时使用 @EnableAsync 注解,使用 @EnableAsync 注解用于开启异步请求. 如 ...
- Visual Studio实用的搜索、查找、替换技巧
前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具,掌握一些Visual Studio实用的搜索.查找.替换技巧可以帮助我们大大提高工作效率从而避免996. Vi ...
- SV Interface and Program
内容 验证平台与待测设计的连接 VTB driver和dut之间的连线通过tb中声明wire连线 通过例化dut的方式进行连接 A module的input连接到B module的output SVT ...
- 【C/C++】 代码质量控制手段
问题引入 多人协作开发的项目,没有统一的代码规范,那么最终的编写状态必定风格迥异,产生的结果:对内,阅读审核代码是很痛苦的:对外,公司形象就是差. 单干的项目也必须要严格按照代码规范,因为最终还是会对 ...
- java - 对象装载数据传递到方法中
1. 创建 Phone 类 package class_object; public class Phone { String brand; String color; double price; v ...