Trie树入门
孔子有言“温故而知新”,由于近期复习了
处理的问题
其实
步骤
大体的板子的步骤其实非常简单,在这就提一嘴罢:
- 初始化
树(谨防多侧),把表示节点个数的 和表示边的 数组全部清零,我们可以认为 号节点存在,是第一个节点,有他指向字符串里的第一个字符。 函数,进行插入,从根节点开始访问,按照当前字符串里的字符作为边的值指向子节点,如果没有,则动态新建一个 函数,进行查询,总体的遍历方式和插入一样,只是过程中不要新建节点,而且要在函数中维护要查询的东西即可。
再单独列出
-
根节点是一个空节点
一定要给根节点留出位置
-
采取动态开点方式
如果当前节点已经有当前串下一个位置的字符这个儿子,那么就不用建立,否则要建立一个新的儿子。
可以借助此图理解理解(一张高清大图):
例题
选了
T1
题意:
给定一棵
题解:
随便指定一个
之后我们利用
这道题本质是一个性质及
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define L(i, a, b) for(int i = a; i <= b; i++)
#define R(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
const int N = 1e6 + 10;
struct A{
int v, w;
};
int n, val[N], mx;
vector<A> g[N];
struct Trie{
int t[N * 2][2], tot;
void Init(){
tot = 0;
memset(t, 0, sizeof(t));
}
void Insert(int x){
int p = 0;
R(i, 30, 0){
int now = (bool)(x & (1 << i));
if(!t[p][now])
t[p][now] = ++tot;
p = t[p][now];
}
}
int Query(int x){
int p = 0, sum = 0;
R(i, 30, 0){
int now = (bool)(x & (1 << i));
if(t[p][now ^ 1])
p = t[p][now ^ 1], sum += 1 << i;
else
p = t[p][now];
}
return sum;
}
} t;
void dfs(int x, int p){
t.Insert(val[x]);
mx = max(mx, t.Query(val[x]));
for(A e: g[x]){
int v = e.v, w = e.w;
if(v == p) continue;
val[v] = w ^ val[x];
dfs(v, x);
}
}
int main(){
while(~scanf("%d", &n)){
mx = 0, t.Init();
L(i, 1, n) g[i].clear();
L(i, 1, n - 1){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
g[u].push_back((A){v, w});
g[v].push_back((A){u, w});
}
val[1] = 0;
dfs(1, 0);
printf("%d\n", mx);
}
return 0;
}
T2
POJ2513——道巨水的题。 这里之所以要拿出来,是因为它是通过trie树进行模型转换的一个代表。 那我们
题意:给你一些木棍,木棍首尾分别各有一个单词,请将所有木棍排成一行,使得任意相邻的木棍相接处的单词一样。
题解:我们把单词插入字典树中变成数字编号,不难发现木棍变成了边,数字编号是点的编号,因为是一条而不是一个环,我们只要求是否存在欧拉通路即可。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define L(i, a, b) for(int i = a; i <= b; i++)
#define R(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
const int N = 500010;
int n, m, d[N];
pair<int, int> e[N];
struct Trie{
int tot, c[N], trie[N][26];
int Insert(char *s){
int p = 0, l = strlen(s);
if(s[l - 1] == '\n') l--;
L(i, 0, l - 1){
int v = s[i] - '0';
if(!trie[p][v]) trie[p][v] = ++tot;
p = trie[p][v];
}
if(!c[p]) c[p] = ++n;
return c[p];
}
} t;
struct DSU{
int fa[N];
void Init(){
L(i, 1, n) fa[i] = i;
}
int Find(int x){
return x == fa[x]? x : fa[x] = Find(fa[x]);
}
void Union(int x, int y){
x = Find(x), y = Find(y);
fa[x] = y;
}
} dsu;
int main(){
char s[23], a[12], b[12];
while(fgets(s, 23, stdin) != NULL){
sscanf(s, "%s %s", a, b);
e[++m] = make_pair(t.Insert(a), t.Insert(b));
}
dsu.Init();
L(i, 1, m){
dsu.Union(e[i].first, e[i].second);
d[e[i].first]++, d[e[i].second]++;
}
int cnt = 0;
L(i, 1, n){
if(dsu.Find(i) != dsu.Find(1)){
puts("Impossible");
return 0;
}
if(d[i] & 1) cnt++;
}
if(!cnt || cnt == 2){
puts("Possible");
}
else{
puts("Impossible");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通