字典树Trie
字典树Trie
结构:
trie的结构就是一个类似于前缀匹配的结构,我们用
应用:
简单查找字符串:
建立一颗由小写字母为字符集组成的Trie树,每次查询都从根节点开始,一个一个向下查找,如果在某个节点发现没有下个节点的字母与当前要询问的名字的字母相同时,则为 WRONG
,如果存在该名字,我们对这个末尾节点开一个计数的数,如果这个数 REPEAT
,否则输出 OK
。
code:
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1e4 + 7;
int cnt = 1,trie[MAXN * 50][27];
int has[MAXN * 50];
int n,m;
string s;
void insert(string s){
int len = s.length(),p = 1;
for(int i = 1;i <= len;i++){
if(trie[p][s[i - 1] - 'a']) p = trie[p][s[i - 1] - 'a'];
else cnt++,trie[p][s[i - 1] - 'a'] = cnt,p = cnt;
}
has[p] = 1;
}
int find(string s){
int len = s.length(),p = 1;
for(int i = 1;i <= len;i++){
if(trie[p][s[i - 1] - 'a']) p = trie[p][s[i - 1] - 'a'];
else return 2;
}
if(has[p] == 1) return has[p]++,0;
else return has[p]++,1;
}
int main(){
scanf("%d", &n);
for(int i = 1;i <= n;i++) cin >> s,insert(s);
scanf("%d", &m);
for(int i = 1;i <= m;i++){
cin >> s;
if(find(s) == 0) printf("OK\n");
else if(find(s) == 1) printf("REPEAT\n");
else printf("WRONG\n");
}
return 0;
}
代码好实现。
最长异或路径
[P4551 最长异或路径](P4551 最长异或路径)
我们已知异或具有前缀和的性质,那么我们设根节点为
即求
我们预处理出
建立一颗 01 Trie
树,把
然后枚举
这实际上是一种贪心的思想,因为从高位到低位,我们如果二进制位上的值相反
,那么就选择这一位,因为高位上的值价值大于低位。所以我们建树的过程也是从高位往低位建树。
那么复杂度就是
code:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 1e5 + 7;
const int LOG = 30;
struct EDGE{ int x,val; };
int n, x, y, v;
vector<EDGE> tree[MAXN];
int val[MAXN];
int cnt = 1, trie[MAXN * LOG][2], ans;
void insert(int val){
int p = 1;
for(int i = 30;i >= 0;i--){
int op = ((val >> i) & 1);
if(trie[p][op]) p = trie[p][op];
else cnt++,trie[p][op] = cnt,p = cnt;
}
}
void dfs(int pos,int fa){
for(auto to : tree[pos]) if(to.x != fa) val[to.x] = to.val ^ val[pos],insert(val[to.x]),dfs(to.x,pos);
}
void cal(int pos){
int res = 0,p = 1;
for(int i = 30;i >= 0;i--){
int op = (val[pos] >> i) & 1;
if(trie[p][op ^ 1]) p = trie[p][op ^ 1], res = res | (1 << i);
else p = trie[p][op];
}
ans = max(ans,res);
}
void dfs1(int pos,int fa){
cal(pos);
for(auto to : tree[pos]) if(to.x != fa) dfs1(to.x,pos);
}
int main(){
scanf("%d", &n);
for(int i = 1;i <= n - 1;i++) {
scanf("%d%d%d", &x, &y, &v);
tree[x].push_back({y,v}),tree[y].push_back({x,v});
}
dfs(1,0),dfs1(1,0);
printf("%d", ans);
return 0;
}
Secret Message G
P2922 [USACO08DEC] Secret Message G
题意:
贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息.
信息是二进制的,共有
对于每条暗号
在输入文件中,位的总数(即
题目中提到了 前缀
那么我们自然而然的想到Trie树去进行字符串匹配,我们可以对约翰的
- 查询的字符串的前缀等于原字符串。
- 原字符串的前缀等于查询的字符串。
对于第一类问题,我们对Trie的每一个节点建立
对于第二类问题,我们也对Trie的每一个节点建立
统计答案时,将奶牛的信息字符串放到Trie中进行匹配,在匹配过程中,将经过的
code:
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 500005;
int n,m;
int trie[MAXN * 2][2],a[MAXN],tot = 1,val[MAXN * 2],pre[MAXN * 2];
void insert(int len){
int p = 1;
for(int i = 1;i <= len;i++){
if(trie[p][a[i]]) p = trie[p][a[i]];
else tot++,trie[p][a[i]] = tot,p = tot;
val[p]++;
}
val[p]--;
pre[p]++;
}
int find(int len){
int p = 1,res = 0;
for(int i = 1;i <= len;i++){
if(trie[p][a[i]]) p = trie[p][a[i]],res += pre[p];
else {p = trie[p][a[i]]; break;}
}
return res + val[p];
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1;i <= n;i++){
int len;scanf("%d", &len);
for(int i = 1;i <= len;i++) scanf("%d", &a[i]);
insert(len);
}
for(int i = 1;i <= m;i++){
int len;scanf("%d", &len);
for(int i = 1;i <= len;i++) scanf("%d", &a[i]);
printf("%d\n", find(len));
}
return 0;
}
本文来自博客园,作者:wyl123ly,转载请注明原文链接:https://www.cnblogs.com/wyl123ly/p/18541967
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· 一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略