最长异或路径

题目链接:ybt高效进阶2-4-3 / luogu P4551

题目大意

给定一棵 n 个点的带权树,结点下标从 1 开始到 N。寻找树中找两个结点,求最长的异或路径。

异或路径指的是指两个结点之间唯一路径上的所有边权的异或。

思路

首先看到要异或的值最大,我们要想到可以用 Trie 树来贪心弄。

但是它好像不知道怎么弄,那我们先不管它。

那我们看到是一棵树,那我们可以试着统计 \(i\) 到根节点(我这里设是 \(1\))的异或路径的长度是多少。

那我们考虑能不能用这个表示出任意两个点之间的异或路径。

这里先给出结论,其实就是两个点到根节点的异或路径异或起来得出的值。

我们来证明:

分两种情况,分别是一个点在另一个点到根节点的路径上,要么就是两条路径是分开的,不会相交。

  1. 第一种,那我们可以知道一个点,就是一个值异或它自己就是 \(0\),就会消掉。那你想想,第一种情况时这个图:



    那 \(1\) 号点到根节点的异或路径就是 \(a\),\(2\) 号点到根节点的异或路径是 \(a\oplus b\),我们要的是 \(b\)。

    那你发现,把它们异或起来,就是 \(a\oplus a\oplus b=b\)。(两个 \(a\) 异或起来抵消掉了)
  2. 第二种,那我们可以画图。



    那 \(1\) 号点到根节点的异或路径就是 \(a\),\(2\) 号点到根节点的异或路径是 \(b\),我们要的是 \(a\oplus b\)。

    那你发现,把它们异或起来,就是 \(a\oplus b\)。

那你就可以一开始预处理出到根节点的异或路径,然后枚举两个点,然后算这两个点的异或路径,然后取最大值。

但是很明显这样是 \(O(n^2)\) 的,它会超时。

那我们就想一想有什么方法可以快速求最大值的。

想想我们之前一开始想用什么方法?

没错,就是 Trie 树。

我们可以把每个点到根节点的异或路径都放进 Trie 树里面构造。

然后每次枚举你要的异或路径的另一个点,然后跟 Trie 树里面的路径匹配找到最大值。

前面做过一题就是求这个最大值的,主要的就是用了贪心的思想。

从高位向低位枚举,然后如果有跟你这一位不同的就优先选,同时统计这一位异或之后是 \(1\) 对数的贡献。然后如果没有不同的,就看有没有相同的。

(因为毕竟你可以这一位相同,然后尽可能让后面更高的位不同,这样的贡献就更大)

那如果想相同不相同都没有,那就只能以当前的贡献退出了。

(如果想看之前的那一题可以点我查看,不过我只写在了 csdn,博客园里没有,因为比较简单)

然后对这些最大值选一个最大的,就是答案了。

代码

  1. #include<cstdio>
  2. #include<iostream>
  3. using namespace std;
  4. struct node {
  5. int x, to, nxt;
  6. }e[200001];
  7. struct Tree {
  8. int son[2];
  9. }trie[1000001];
  10. int n, x, y, z, le[100001], KK, go, KKK, ans;
  11. void add(int x, int y, int z) {//邻接表
  12. e[++KK] = {z, y, le[x]}; le[x] = KK;
  13. e[++KK] = {z, x, le[y]}; le[y] = KK;
  14. }
  15. void build(int num) {//Trie树建树
  16. int now = 0;
  17. for (int i = 31; i >= 0; i--) {
  18. go = num >> i & 1;
  19. if (!trie[now].son[go]) trie[now].son[go] = ++KKK;
  20. now = trie[now].son[go];
  21. }
  22. }
  23. int find(int num) {
  24. int now = 0, re = 0;
  25. for (int i = 31; i >= 0; i--) {//从高位到低位贪心看
  26. go = num >> i & 1;
  27. if (trie[now].son[go ^ 1]) {//先看能不能有这一位不同
  28. now = trie[now].son[go ^ 1];
  29. re |= 1 << i;
  30. }
  31. else if (trie[now].son[go]) now = trie[now].son[go];//只能相同
  32. else return re;//都没有,就只能退出了
  33. }
  34. return re;
  35. }
  36. void dfs1(int now, int father, int num) {//建出从根节点到 i 点的异或路径构成的 Trie 数
  37. build(num);
  38. for (int i = le[now]; i; i = e[i].nxt)
  39. if (e[i].to != father)
  40. dfs1(e[i].to, now, num ^ e[i].x);
  41. }
  42. void dfs2(int now, int father, int num) {//得出与现在的路径异或能得到的最大值
  43. ans = max(ans, find(num));
  44. for (int i = le[now]; i; i = e[i].nxt)
  45. if (e[i].to != father)
  46. dfs2(e[i].to, now, num ^ e[i].x);
  47. }
  48. int main() {
  49. scanf("%d", &n);
  50. for (int i = 1; i < n; i++) {
  51. scanf("%d %d %d", &x, &y, &z);
  52. add(x, y, z);
  53. }
  54. dfs1(1, 0, 0);
  55. dfs2(1, 0, 0);
  56. printf("%d", ans);
  57. return 0;
  58. }

【ybt高效进阶2-4-3】【luogu P4551】最长异或路径的更多相关文章

  1. [luogu] P4551 最长异或路径(贪心)

    P4551 最长异或路径 题目描述 给定一棵\(n\)个点的带权树,结点下标从\(1\)开始到\(N\).寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或 ...

  2. Luogu P4551 最长异或路径

    题目链接 \(Click\) \(Here\) \(01Trie\)好题裸题. 取节点\(1\)为根节点,向下扫每一个点从根节点到它路径上的异或和,我们可以得到一个\(sumx[u]\). 现在路径异 ...

  3. Luogu P4551 最长异或路径 01trie

    做一个树上前缀异或和,然后把前缀和插到$01trie$里,然后再对每一个前缀异或和整个查一遍,在树上从高位向低位贪心,按位优先选择不同的,就能贪出最大的答案. #include<cstdio&g ...

  4. 洛谷P4551 最长异或路径

    传送门:https://www.luogu.org/problem/show?pid=4551 在看这道题之前,我们应懂这道题怎么做:给定n个数和一个数m,求m和哪一个数的异或值最大. 一种很不错的做 ...

  5. 2018.10.26 洛谷P4551 最长异或路径(01trie)

    传送门 直接把每个点到根节点的异或距离插入01trie. 然后枚举每个点在01trie上匹配来更新答案就行了. 代码: #include<iostream> #include<cst ...

  6. P4551 最长异或路径

    题目描述 给定一棵 nnn 个点的带权树,结点下标从 111 开始到 NNN .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或. 输入输出格式 输入格式 ...

  7. 洛谷 P4551 最长异或路径

    题目描述 给定一棵 nn 个点的带权树,结点下标从 11 开始到 NN .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有节点权值的异或. 输入输出格式 输入格式: ...

  8. P4551 最长异或路径 (01字典树,异或前缀和)

    题目描述 给定一棵 n 个点的带权树,结点下标从 1 开始到 N .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或. 输入输出格式 输入格式: 第一行一 ...

  9. 洛谷【P4551】最长异或路径

    浅谈\(Trie\):https://www.cnblogs.com/AKMer/p/10444829.html 题目传送门:https://www.luogu.org/problemnew/show ...

随机推荐

  1. 【Linux】NFS搭建及使用详解

    环境:CentOS release 6.8 server  192.168.25.100 client1 192.168.25.101 client2 192.168.25.102 1.服务端操作 1 ...

  2. leetcode 864. 获取所有钥匙的最短路径(BFS,状态压缩)

    题目链接 864. 获取所有钥匙的最短路径 题意 给定起点,要求在最短步骤内收集完所有钥匙,遇到每把锁之前只有 有对应的钥匙才能够打开 思路 BFS+状态压缩典型题目 先确定起点和总的钥匙数目,其次难 ...

  3. ctfshow—web—web2

    打开靶机,根据提示是SQL注入 打开后看到登录窗口 方法一.手工注入 抓取数据包 开始SQL注入测试 利用万能密码,登录成功 查看回显位置 查询数据库 查询数据库内数据表 如果想整齐一点显示可以添加g ...

  4. 力软最新版本与.netCore版本

    功能强大,直接上图: 加微信或QQ交流开发技术:25489181 netcore版本 版本优势: .NET Core是适用于 Windows.Linux 和 macOS 的免费.开源托管的计算机软件框 ...

  5. 在EXCEL中如何同时冻结行与列?

    鼠标所在的单元格的位置 ,决定了你冻结的行和列.如: 冻结第一行与第一列, 只需要将鼠标置于单元格在第二列,第二行. 点击冻结

  6. Vue之事件绑定

    Vue事件绑定 点击事件 @click="事件名" or v-on:click="事件名" 结构部分: <el-button type="pri ...

  7. ip_hash(不推荐使用) 会话粘性问题分析 Cookie 的 Session Sticky

    Nignx 连接tomcat时会话粘性问题分析_changyanmanman的专栏-CSDN博客_后端tomcat导致 前端elb中断 https://blog.csdn.net/cymm_liu/a ...

  8. py, pyc, pyw, pyo, pyd Compiled Python File (.pyc) 和Java或.NET相比,Python的Virtual Machine距离真实机器的距离更远

    https://my.oschina.net/renwofei423/blog/17404 1.      PyCodeObject与Pyc文件 通常认为,Python是一种解释性的语言,但是这种说法 ...

  9. C++ Primer Plus读书笔记(一)开始学习C++

    1.using namespace std; 注意一下命名空间的概念,不编译这句话,可能就要用  std::cout << std::endl 这种写作方式了. 这句话放在函数内部,只对该 ...

  10. Python 学习笔记(1)

    Mac下载安装Python mac 系统自带有python .但就最新的mac系统而言,它自带的python版本为2.*版本. 虽然不影响对于老python项目的运行,但3.*版本中很多语法都发生了改 ...