前言

如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。

题意

给定一颗 nnn 个点的树,每条边的权重为 wiw_iwi​。(2≤n≤105,0≤wi<230)(2\leq n\leq 10^5,0\leq w_i< 2^{30})(2≤n≤105,0≤wi​<230)

可以任意删除一些边或者增加一些边,但是在删增过程中必须保证图连通并且任意一个环的异或和为 000。

在此基础上,求最小生成树。

题目链接:linklinklink


思路

观察题目要求,删增过程中保证图连通且任意一个环的异或和为 000,所以其实 (u,v)(u,v)(u,v) 边的权重是已经确定的,即两点之间边的异或和。

确定完边权后,问题就转换为了对于一个 nnn 个点的完全图,求最小生成树。

为了解决这个问题,我们先了解一下 BoruvkaBoruvkaBoruvka 算法:linklinklink

BoruvkaBoruvkaBoruvka 算法主要针对这些问题:nnn 个点,每个点有点权,任意两个点之间有边权,边权为两个点权用某种计算方式得出,求最小生成树。

对于这些问题,我们通常用 O(log(n))O(log(n))O(log(n)) 的时间找到与点 iii 连边的边权最小的 jjj,具体生成树算法如下:

  1. 考虑维护当前的连通块(初始每个点为独立的一个连通块)
  2. 对每个连通块,找到一条与该连通块相连的,且另一端点不在此连通块中的边权最小的边
  3. 将所有的这些边都加入最小生成树,注意,当加入一条边时需判断该边的两端点是否在同一连通块
  4. 重复若干遍上述操作,直到图连通

上述算法即为 BoruvkaBoruvkaBoruvka 算法,每次操作完,连通块个数至少减半,则复杂度为 O((n+m)log(n))O((n+m)log(n))O((n+m)log(n))(并查集复杂度为常数)

在本题中,我们可以先以 111 为起点,求出 111 号点到每一个点的异或和 d[i]d[i]d[i],任意两点 u,vu,vu,v 的边权即为 d[u]xord[v]d[u]\ xor\ d[v]d[u] xor d[v]。因此题目转换成,每一个点都有一个权值 d[i]d[i]d[i],任意一条边 (u,v)(u,v)(u,v) 的边权为 d[u]xord[v]d[u] \ xor \ d[v]d[u] xor d[v],求最小生成树。

这个问题即为最小异或生成树问题,可以采用 BoruvkaBoruvkaBoruvka 思想来解决。

首先,由于涉及到了异或,因此引入字典树是非常常见的操作。我们将每一个点的权值从高位到低位依次插入字典树中,然后遍历字典树求答案。对于字典树节点 xxx,当前深度为 stepstepstep,我们令其 000 号儿子为 lxlxlx,111 号儿子为 rxrxrx。

若 lxlxlx 与 rxrxrx 只有一个存在,则一定不存在一条边,其边权中包含 1<<step1<<step1<<step,即继续往下递归即可。

若 lxlxlx 与 rxrxrx 均存在,则一定存在一条边,连接左右两部分,即边权中包含 1<<step1<<step1<<step,因此我们还需要从 lxlxlx 和 rxrxrx 中分别找到一个数字,使其异或值最小。此处可以直接采用贪心的思想,尽可能令每一位的数相同,贪心向下搜索,平均复杂度为 O(log(n))O(log(n))O(log(n)),具体过程见下述代码。

因此本题总复杂度为遍历字典树 +++ 每个节点找最小值,即 O(nlog2(n))O(nlog^2(n))O(nlog2(n))。


代码

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = a; i <= b; i++)
typedef long long ll;
const int N = 3e6+10;
using namespace std;int n, tot, trie[N][3];
ll d[N];
vector<pair<int, ll> > G[N];void dfs1(int x, int fa) {for(auto it:G[x]) {int y = it.first;ll w = it.second;if(y == fa) continue;d[y] = d[x]^w;dfs1(y,x);}
}void insert(ll w) {int cur = 0;for(int i = 30; i >= 0; i--) {int v = ((w&(1<<i)) > 0);if(!trie[cur][v]) trie[cur][v] = ++tot;cur = trie[cur][v];       }
}ll find(int x, int y, int step) {if(step < 0) return 0;int lx = trie[x][0], rx = trie[x][1];int ly = trie[y][0], ry = trie[y][1];ll minn = 1e15;if(lx) {if(ly) minn = min(minn, find(lx, ly, step-1));else minn = min(minn, find(lx, ry, step-1) + (1<<step));}if(rx) {if(ry) minn = min(minn, find(rx, ry, step-1));else minn = min(minn, find(rx, ly, step-1) + (1<<step));}return minn;
}ll dfs2(int cur, int step) {int ls = trie[cur][0], rs = trie[cur][1];ll ans = 0;if(ls && rs) ans += find(ls, rs, step-1) + (1<<step);if(ls) ans += dfs2(ls, step-1);if(rs) ans += dfs2(rs, step-1);return ans;
}int main()
{scanf("%d",&n);rep(i,1,n-1) {int u,v,w; scanf("%d%d%d",&u,&v,&w);G[u].push_back({v,w});G[v].push_back({u,w});}dfs1(0, -1);rep(i,0,n-1) insert(d[i]);printf("%lld\n", dfs2(0, 30));return 0;
}

【Nowcoder - 5670 B Graph】2020 牛客暑期多校训练营(第五场)【最小异或生成树、Boruvka 思想】相关推荐

  1. E Groundhog Chasing Death(2020牛客暑期多校训练营(第九场))(思维+费马小定理+质因子分解)

    E Groundhog Chasing Death(2020牛客暑期多校训练营(第九场))(思维+费马小定理+质因子分解) 链接:https://ac.nowcoder.com/acm/contest ...

  2. 2020牛客暑期多校训练营(第一场)

    文章目录 A B-Suffix Array B Infinite Tree C Domino D Quadratic Form E Counting Spanning Trees F Infinite ...

  3. 2020牛客暑期多校训练营(第二场)

    2020牛客暑期多校训练营(第二场) 最烦英语题 文章目录 A All with Pairs B Boundary C Cover the Tree D Duration E Exclusive OR ...

  4. 2020牛客暑期多校训练营(第一场)A B-Suffix Array(后缀数组,思维)

    链接:https://ac.nowcoder.com/acm/contest/5666/A 来源:牛客网 题目描述 The BBB-function B(t1t2-tk)=b1b2-bkB(t_1 t ...

  5. 2020牛客暑期多校训练营(第二场)Just Shuffle

    https://ac.nowcoder.com/acm/contest/5667/J 题目大意:给你一个置换A,使得置换P^k=A,让你求出置换P. 思路:我们根据置换A再置换z次,那么就等于置换p ...

  6. 2020牛客暑期多校训练营(第一场)j-Easy Integration(思维,分数取模,沃斯利积分)

    题目链接 题意: 给你一个积分公式,给你一个n,问积分公式的值取模后的结果. 思路: 积分公式(沃利斯积分)值的结论直接就是(n!)^2/(2n+1)!,求个阶乘,再用费马小定理给1/(2n+1)!取 ...

  7. 2020 牛客暑期多校训练营(第一场)F

    题目大意: 多次输入两个a,b字符串他们可以无限次的重复变成aaa,或者bbb 比较他们的大小,相同输出 =,a<b输出 <,a>b输出 >. 输入: aa b zzz zz ...

  8. 2020牛客暑期多校训练营(第二场)未完待续......

    F. Fake Maxpooling 题目: 题目大意: 输入n,m,k.矩阵的尺寸为nm,其中每一个元素为A[i][j] = lcm( i , j ).从中找出所有kk的子矩阵中元素最大的数之和. ...

  9. 2020牛客暑期多校训练营(第一场)J、Easy Integration (数学、分部积分)

    题目链接 题面: 题意: 求给定的定积分. 题解,化成 ∫ xn (1-x)n dx 然后用分部积分法即可得. 分部积分法:∫ udv = uv - ∫ vdu 最终为 n!/((n+1)*(n+2) ...

  10. 2020牛客暑期多校训练营(第二场)题解

    废话 蒟蒻不会积分,K不会做. 文章目录 废话 A. All with Pairs B. Boundary C. Cover the Tree D. Duration E. Exclusive OR ...

最新文章

  1. python实现三种以上判断条件_Python小课笔记--Python控制流:if逻辑判断
  2. 如何用PHP写商品折扣_秒杀抢购时的超发,你用php如何优化的
  3. boost::execution_monitor相关的测试程序
  4. idea会抛出Unable to import maven project: See logs for details错误
  5. 牛客网 【每日一题】5月29日 管道取珠
  6. POJ2083-Fractal【分形,分治】
  7. 动态规划之91 decode ways
  8. docker+kafka+zookeeper+zipkin的安装
  9. 怎样验证软件是否可信?是否被篡改?
  10. vimpython配色_超漂亮 vim 配置:space-vim
  11. Java开发笔记(一百三十一)Swing的列表框
  12. restlet java_restlet(javase版本) 的最基本使用
  13. excel进销存添加网页模块,可手机开单
  14. 036--python--摇骰子游戏
  15. 2018再见|2019你好
  16. matlab传递函数的分数次方,matlab如何画一个幂函数的曲线?f(x)=(x1)*(x2)^,matlab中如何画出幂函数指数为分数时比如y=x^(1/3...
  17. Java开发工具排名,你知道几个?
  18. 拜托,不要再问我Git如何回滚代码
  19. redis主从架构(上)
  20. 王道考研数据结构笔记之基本概念

热门文章

  1. Android工具箱之文件目录
  2. IIS添加对ashx文件的支持
  3. C#对IE使用Proxy(代理)
  4. 成都程序员俱乐部通知
  5. wordpress文章,页面,小工具如何使用php代码
  6. STC学习:实时时钟
  7. 基本系统设备_正规全体灭火系统承包资质品质更好_天霖工程
  8. directx修复工具 4.0_A12-A13最稳定越狱工具发布,支持iOS13.0—iOS13.3
  9. cuda10安装_Mmdetection的安装和使用
  10. 正解mysql: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /usr/lib64/libstdc++.so.6)