算法竞赛进阶指南——字典树学习笔记
字典树的插入以及删除操作
#include <bits/stdc++.h> using namespace std; #define N 10010 int tire[N][26]; int tot = 1; bool end[N];//如果为真,那么就意味着这一个点是结尾 char buf[N]; void insert(char *s) { int p = 1; int len = strlen(s); for(int i = 0; i < len; i++) { int x = s[i] - 'a'; if(tire[p][x] == 0) tire[p][x] = ++tot; p = tire[p][x]; } end[p] = true; } bool search(char * s) { int p = 1; int len = strlen(s); for(int i = 0; i < len; i++) { p = tire[p][s[i]-'a']; if(!p) return false; } return end[p]; } int main() { int n, m; cin >> n >> m; for(int i = 1; i <= n; i++) { scanf("%s", &buf); insert(buf); } for(int i = 1; i <= m; i++) { scanf("%s", buf); if(search(buf)) printf("yes\n"); else printf("no\n"); } return 0; }
AcWing142. 前缀统计
这道题目很显然会想到使用字典树(应为可以使用树来对不同前缀的进行分叉)
代码
#include <bits/stdc++.h> using namespace std; #define N 1000020 int trie[N][26]; int tot = 1; int cnt[N]; char buf[N]; void ins(char *s) { int p = 1; cnt[p]++; int len = strlen(s); for(int i = 0; i < len; i++) { if(trie[p][s[i]-'a'] == 0) trie[p][s[i]-'a'] = ++tot; p = trie[p][s[i]-'a']; } cnt[p] ++; } int ser(char *s) { int ans = 0; int len = strlen(s); int p = 1; for(int i = 0; i < len; i++) { p = trie[p][s[i]-'a']; if(!p) break; ans += cnt[p]; } return ans; } int main() { int n, m; cin >> n >> m; for(int i = 1; i <= n; i++) { scanf("%s", buf); ins(buf); } for(int i = 1; i <= m; i++) { scanf("%s", buf); printf("%d\n", ser(buf)); } return 0; }
AcWing\143. 最大异或对
字典序就是把
-
这道题目如果使用俩俩逐个进行比较,显然是不行。
-
对于这道题目,我一开始想象,如果随着输入一遍之后直接通过树来得到结果,显然是不行。
对于如图所示的情况,第一层可以选择不相同的,但是第二层不知道是左面是0还是右面是0,这样就需要不断试探。。。。。。
3. 看了一下数据范围,输入数据,需要 O ( n ) O(n) O(n),其实可以使用 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)的算法。
枚举每一个值,贪心找到与他异或最大的数字!
#include <bits/stdc++.h> using namespace std; #define N 3200000 #define M 100010 int trie[N][2]; int tot = 1; int s[M]; void insert(int x) { int p = 1; for(int i = 31; i >= 0; i--) { int z = (x >> i) & 1; if(trie[p][z] == 0) trie[p][z] = ++tot; p = trie[p][z]; } } int search(int x) { int ret = 0; int p = 1; for(int i = 31; i >= 0; i--) { int z = ((x>>i) & 1)^1; if(trie[p][z] != 0) { p = trie[p][z]; ret = (ret << 1) + 1; } else { z = !z; p = trie[p][z]; ret = (ret << 1); } } return ret; } int main() { int ans = 0; int n; cin >> n; for(int i = 1; i <= n; i++) { int in; scanf("%d", &in); s[i] = in; insert(in); } for(int i = 1; i <= n; i++) { int ret = search(s[i]); ans = max(ret, ans); } cout << ans; return 0; }
ACWing\144. 最长异或值路径
对于这道题目,一是摸不着头脑。
因为涉及到树,并不是任意两个点之间都可以进行异或。。。
但是:
树是一种特殊的图,感觉对于树,可以任意拎出来一个节点,当做是根节点,这时候,不是在同一个分支的两个点之间的路径必定经过父亲节点
eg
注意:由于具有相同的值的异或等于0,并且0异或其他的数字相当于没有异或。
只要求出根节点到每一个节点的异或,然后就好了。
代码
#include <bits/stdc++.h> using namespace std; #define N 1000200//竟然是数组开小了 /*树开始*/ int head[N], nxt[N], vis[N], edge[N], arc[N]; int tot = 1;//可以进行对偶(已经知道一条边,那么这条边的id ^ 1就是与他方向相反的边) /*树结束*/ /*字典树开始*/ int trie[N*32][2]; int cnt = 1;//1表示为根节点 /*字典树结束*/ int s[N];//字典树里面的所有元素 int s_cnt = 0; void insert(int x) { s[++s_cnt] = x; int p = 1;//不初始化害死人 for(int i = 31; i >= 0; i--) { int z = (x>>i) & 1; if(trie[p][z]==0) trie[p][z] = ++cnt; p = trie[p][z]; } } void add(int u, int v, int w) { arc[++tot] = v; edge[tot] = w; nxt[tot] = head[u]; head[u] = tot; } void DFS(int T, int sum) { if(vis[T]) return; vis[T] = 1; for(int i = head[T]; i; i = nxt[i]) { int to = arc[i]; if(vis[to]) continue; insert(sum ^ edge[i]); DFS(to, sum ^ edge[i]); } } int search(int x) { int ret = 0; int p = 1; for(int i = 31; i >= 0; i--) { int z = ((x >> i) & 1)^1; if(trie[p][z] != 0) { ret = (ret << 1) + 1; p = trie[p][z]; } else { ret = ret << 1; p = trie[p][1^z]; } } return ret; } int main() { int ans = 0; int n; cin >> n; for(int i = 1; i <= n-1; i++) { int u, v, w; u++;//注意:我这里点是从1开始的 v++; scanf("%d%d%d", &u, &v, &w); add(u, v, w); add(v, u, w); } DFS(1, 0); insert(0);//注意:深度优先并不会添加从root到root的异或值 for(int i = 1; i <= n; i++) { int ret = search(s[i]); ans = max(ans, ret); } cout << ans; return 0; }
本文来自博客园,作者:心坚石穿,转载请注明原文链接:https://www.cnblogs.com/xjsc01/p/16438216.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现