【Coel.学习笔记】【一个阶段的结束】01-Trie树(01字典树)求异或路径
2022/3/31 23:22:00
本文主要是介绍【Coel.学习笔记】【一个阶段的结束】01-Trie树(01字典树)求异或路径,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
题前闲语
是的,变成闲语了(别问我为什么要改)
今天考完了月考,虽然发挥得不是很好但终归是结束了,休息一下~
刚好深进也到货了,开始新一轮学习吧!
题目简介
题目描述
给定一棵 \(n\) 个点的带权树,结点下标从 \(1\) 开始到 \(n\)。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
输入输出格式
输入格式
第一行一个整数 \(n\),表示点数。
接下来 \(n-1\) 行,给出 \(u,v,w\) ,分别表示树上的 \(u\) 点和 \(v\) 点有连边,边的权值是 \(w\)。
输出格式
一行,一个整数表示答案。
解题思路
考虑用链式前向星存图,求出每个节点到根节点(自行定义根节点为\(1\))的异或路径,那么两个节点的异或路径就是它们与根节点路径的异或值。
先用\(dfs\)初始化每个节点的异或值:
struct edge { int next, to, w; } edge[maxn]; int p[maxn], cnt; void add_edge(int u, int v, int w) { edge[++cnt].next = p[u]; edge[cnt].to = v; edge[cnt].w = w; p[u] = cnt; } void init(int x, int f) {//dfs for (int i = p[x]; i != 0; i = edge[i].next) { int v = edge[i].to, w = edge[i].w; if (v != f) { s[v] = s[x] ^ w; init(v, x); } } }
然后暴力枚举。当然直接暴力枚举的话复杂度是\(O(n^2)\),没法通过\(n=10^5\),所以需要用\(01-Trie\)优化。
(此处待补充)
代码如下:
#include <cctype> #include <cstdio> #include <iostream> #include <vector> namespace FastIO { inline int read() { int x = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } inline void write(int x) { if (x < 0) { x = -x; putchar('-'); } static int buf[35]; int top = 0; do { buf[top++] = x % 10; x /= 10; } while (x); while (top) putchar(buf[--top] + '0'); puts(""); } } // namespace FastIO using namespace std; using namespace FastIO; const int maxn = 1e5 + 10; struct edge { int next, to, w; } edge[maxn]; int p[maxn]; int n, cnt, tot, ans; int s[maxn], ch[maxn * 32][2]; void add_edge(int u, int v, int w) { edge[++cnt].next = p[u]; edge[cnt].to = v; edge[cnt].w = w; p[u] = cnt; } void init(int x, int f) { for (int i = p[x]; i != 0; i = edge[i].next) { int v = edge[i].to, w = edge[i].w; if (v != f) { s[v] = s[x] ^ w; init(v, x); } } } void insert(int v) { int u = 0; for (int i = (1 << 30); i; i >>= 1) { bool c = v & i; if (!ch[u][c]) ch[u][c] = ++tot; u = ch[u][c]; } } int find(int v) { int ans = 0, u = 0; for (int i = (1 << 30); i; i >>= 1) { bool c = v & i; if (ch[u][!c]) { ans += i; u = ch[u][!c]; } else u = ch[u][c]; } return ans; } int main() { n = read(); for (int i = 1; i <= n - 1; i++) { int u = read(), v = read(), w = read(); add_edge(u, v, w); add_edge(v, u, w); } init(1, -1); for (int i = 1; i <= n; i++) insert(s[i]); for (int i = 1; i <= n; i++) ans = max(ans, find(s[i])); write(ans); return 0; }
这篇关于【Coel.学习笔记】【一个阶段的结束】01-Trie树(01字典树)求异或路径的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享