题解:CF888G Xor-MST
题解:CF888G Xor-MST
题目大意:给定 \(n\) 个点的点权, 任意两点间边权是点权的异或和。求这张完全图的 MST 的权值。
思路:
Boruvka + Trie树 + 按位贪心。
关键就在于如何求出 Boruvka 中的 best 数组。
考虑对点权建 trie 树,对于节点 \(i\) 本轮的连边,就是找 “和它最相似” 的那个。
我最初的想法是只建一棵 trie 树,那么上述过程只需要每次 尽量 按照 \(a[i]\) 来走就行,但接着就发现不太对,因为求不出 "除去 \(i\) 所在集合中的点权 的影响后的最好方案"。
参考了这篇博客 ,发现给 全局 和 每个集合 分别建树是个很妙的想法,这样就可以轻松减去本集合的权值。具体实现是记录一个 siz 数组。
建树,统计答案都已经实现了,最后合并一下两棵树的信息就行。
感觉难点就在于理清楚思路。比较难写的是merge和query,细节比较多。
时间复杂度 \(O(30nlogn)\)
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
#define pii pair<int, int>
#define fi first
#define se second
using ll = long long;
using namespace std;
const int N = 2e5 +5;
const ll inf = 0x3f3f3f3f;
int a[N], fa[N], best[N], ch[50 * N][2], val[N], root[N], siz[50 * N], tail[50 * N];
int n, num = 0;
inline int get(int x){
return (fa[x]==x) ? x : fa[x] = get(fa[x]);
}
void insert(int &uu, int idx, int w){
if(!uu) uu = ++num;
int u = uu;
G(i, 30, 0){
int o = w >> i & 1;
siz[u] ++ ;
if(!ch[u][o]) ch[u][o] = ++num;
u = ch[u][o];
}
tail[u] = idx; siz[u] = 1;
}
void merge(int &p, int q){
if(!p || !q) return (void)(p = p + q);
merge(ch[p][0], ch[q][0]);
merge(ch[p][1], ch[q][1]);
siz[p] = siz[ch[p][0]] + siz[ch[p][1]];// 合并的一部分, 合并后q就不会再使用了, 所以只操作p就可以了
tail[p] = tail[q];//可以去掉这个赋值? 对于非叶子结点, tail都是0, 但对于叶子结点不清楚 >>>>>>>>>>>>>>>>>>>>>>>>>>
}
pii query(int u, int v, int w){
int ans = 0;
G(i, 30, 0){
int c = (w >> i) & 1;
if(ch[u][c] && siz[ch[u][c]] - siz[ch[v][c]] > 0) u = ch[u][c], v = ch[v][c];
else ans |= (1 << i), u = ch[u][c ^ 1], v = ch[v][c ^ 1];//v 的 移动本质上是 u 的同步, 所以都要 c ^ 1
}
return make_pair(tail[u], ans);//最后选中了哪个点, 代价是多少
}
ll boruvka(){
F(i, 1, n) fa[i] = i;
int pd = 1;
ll sum = 0;
while(pd){
pd = 0;
F(i, 1, n) val[i] = inf, best[i] = 0;
F(i, 1, n){
int x = get(i);
pii ret = query(root[0], root[x], a[i]);//找和a[i]异或得到的结果最小的点
int y = get(ret.fi), w = ret.se;
//注意y要找祖先!
if(x != y){//不在同一集合才能连
if(w < val[x]) best[x] = y, val[x] = w;
if(w < val[y]) best[y] = x, val[y] = w;
}
}
F(i, 1, n){
if(val[i] < inf && get(i) != get(best[i])){
//不用判 best[i]!=0, 因为如果=0, 那val[i]必然=inf, 这也是为什么best可以不清空的原因
sum += val[i];
pd = 1;
merge(root[get(i)], root[get(best[i])]);
fa[get(best[i])] = get(i);
}
}
}
return sum;
}
signed main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n; F(i, 1, n) cin >> a[i];
sort(a + 1, a + 1 + n);
n = unique(a + 1, a + 1 + n) - a - 1;//要去重, 相同权值的点连边其实可以全部等效在一个点上, 而且不去重算出来的siz会加倍, 问题就多了
F(i, 1, n)insert(root[0], i, a[i]), insert(root[i], i, a[i]);
cout << boruvka() << '\n';
return 0;
}
题解:CF888G Xor-MST的更多相关文章
- [题解] [AtCoder2134] Zigzag MST
题面 题解 考虑kruscal的过程 对于三个点\(x, y, x + 1\), 我们可以将\((x, y, z), (y, x + 1, z + 1)\)看做\((x, y, z), (x, x + ...
- 题解-CF617E XOR and Favorite Number
题面 CF617E XOR and Favorite Number 给定 \(n,m,k\) 和 \(n\) 个数的序列 \(a_i\),\(m\) 次求区间 \([l,r]\) 中异或值为 \(k\ ...
- 题解 [AT2134] Zigzag MST
题面 解析 我们先考虑一下加一条边(x,y,z)会成什么亚子: (还有很多边不画了...) 然后我们把这个图单独拿出来: 我们可以发现,对于最小生成树的贡献, 它是等价于下面这张图的(因为连通性一样) ...
- CodeForces 979 D Kuro and GCD and XOR and SUM
Kuro and GCD and XOR and SUM 题意:给你一个空数组. 然后有2个操作, 1是往这个数组里面插入某个值, 2.给你一个x, k, s.要求在数组中找到一个v,使得k|gcd( ...
- BZOJ3390: [Usaco2004 Dec]Bad Cowtractors牛的报复
3390: [Usaco2004 Dec]Bad Cowtractors牛的报复 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 43 Solved: ...
- [Luogu 3690]【模板】Link Cut Tree (动态树)
Description 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和. ...
- bzoj 1954 & poj 3764 The xor-longest Path dfs+Trie
题目大意 给定一棵n个点的带权树,求树上最长的异或和路径 题解 因为\(xor\)操作满足可结合性,所以有 \(a\text{ }xor\text{ }b\text{ }xor\text{ }b = ...
- NOIP模拟 17.9.28
公交车[问题描述]市内有
- 题解-AtCoder Code-Festival2017 Final-J Tree MST
Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...
- BZOJ2337:[HNOI2011]XOR和路径——题解
+++++++++++++++++++++++++++++++++++++++++++ +本文作者:luyouqi233. + +欢迎访问我的博客:http://www.cnblogs.com/luy ...
随机推荐
- 朋友吐槽我为什么这么傻不在源生成器中用string.GetHashCode, 而要用一个不够优化的hash方法
明明有更好的hash方法 有位朋友对我吐槽前几天我列举的在源生成器的生成db映射实体的优化点 提前生成部分 hashcode 进行比较 所示代码 public static void Generate ...
- 别再被坑了! JavaScript类型检测的最佳实践
别再被坑了! JavaScript类型检测的最佳实践 在 JavaScript 中,我们经常需要判断一个变量的类型.这个需求在编程中非常常见,因为不同类型的数据会影响到我们的代码逻辑. JavaScr ...
- 树莓派CM4(二): UART/IIC/SPI调试
1. 参考资料 资料汇总页面 https://shumeipai.nxez.com/raspberry-pi-datasheets <bcm2711-peripherals.pdf>,下载 ...
- 一文带你理解URI 和 URL 有什么区别?
当我们打开浏览器,要访问一个网站或者一个ftp服务器的时候,一定要输入一串字符串, 比如: https://blog.csdn.net/ 或者: ftp://192.168.0.111/ 这样我们就可 ...
- Windows 10 美化 Mac OSX 实用教程
我前几天给新电脑装上了Windows 10系统,想要美化一下,遇到了很多问题,就出了这篇博客,帮大家踩踩坑. 在开始之前,先提醒大家一句: 美化有风险,玩机需谨慎.为以防万一,请大家在进行任何操作前创 ...
- 玄机蓝队靶场_应急响应_02:apache日志分析
日志分析这块,感觉都是对grep.awk.sort.wc.uniq,这几个命令的使用. 一:靶场 (1)直接cd到linux日志, cd /var/log 发现apache2目录, cd ./apac ...
- el-submenu 设定title不显示
原因为 插槽中有空格 slot=" title" 修改为 slot="title"即可
- dotnet 读 WPF 源代码笔记 从 WM_POINTER 消息到 Touch 事件
本文记录我读 WPF 源代码的笔记,在 WPF 底层是如何从 Win32 的消息循环获取到的 WM_POINTER 消息处理转换作为 Touch 事件的参数 由于 WPF 触摸部分会兼顾开启 Poin ...
- Angular Material 18+ 高级教程 – Custom Themes for Material Design 3 (自定义主题 Material 3)
v18 更新重要说明 从 Angular Material v18 开始,默认使用的是 Material 3 Design (简称 M3). 而且是正式版,不再是 experimental previ ...
- Facebook – Facebook Page Embed
前言 在网站嵌套 Facebook 专页是很好的推广方式哦. 虽然网站还是需要做 Blog, 但是通常被订阅的都是 Facebook 专页而不是网站 Blog. 开通账号 它的 setup 很简单, ...