题解: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的更多相关文章

  1. [题解] [AtCoder2134] Zigzag MST

    题面 题解 考虑kruscal的过程 对于三个点\(x, y, x + 1\), 我们可以将\((x, y, z), (y, x + 1, z + 1)\)看做\((x, y, z), (x, x + ...

  2. 题解-CF617E XOR and Favorite Number

    题面 CF617E XOR and Favorite Number 给定 \(n,m,k\) 和 \(n\) 个数的序列 \(a_i\),\(m\) 次求区间 \([l,r]\) 中异或值为 \(k\ ...

  3. 题解 [AT2134] Zigzag MST

    题面 解析 我们先考虑一下加一条边(x,y,z)会成什么亚子: (还有很多边不画了...) 然后我们把这个图单独拿出来: 我们可以发现,对于最小生成树的贡献, 它是等价于下面这张图的(因为连通性一样) ...

  4. 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( ...

  5. BZOJ3390: [Usaco2004 Dec]Bad Cowtractors牛的报复

    3390: [Usaco2004 Dec]Bad Cowtractors牛的报复 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 43  Solved:  ...

  6. [Luogu 3690]【模板】Link Cut Tree (动态树)

    Description 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和. ...

  7. bzoj 1954 & poj 3764 The xor-longest Path dfs+Trie

    题目大意 给定一棵n个点的带权树,求树上最长的异或和路径 题解 因为\(xor\)操作满足可结合性,所以有 \(a\text{ }xor\text{ }b\text{ }xor\text{ }b = ...

  8. NOIP模拟 17.9.28

    公交车[问题描述]市内有

  9. 题解-AtCoder Code-Festival2017 Final-J Tree MST

    Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...

  10. BZOJ2337:[HNOI2011]XOR和路径——题解

    +++++++++++++++++++++++++++++++++++++++++++ +本文作者:luyouqi233. + +欢迎访问我的博客:http://www.cnblogs.com/luy ...

随机推荐

  1. Quartz.NET 的使用

    先貼使用代碼: 1 using Quartz; 2 using Quartz.Impl; 3 using Quartz.Logging; 4 using System; 5 using System. ...

  2. CORDIC算法解释及FPGA实现(圆坐标系)

    CORDIC算法解释及Verilog仿真(圆坐标系) CORDIC算法原理阐述 CORDIC(Coordinate Rotation Digital Computer)算法,即坐标旋转数字计算方法,是 ...

  3. Redis分布式锁防止缓存击穿

    一.Nuget引入 StackExchange.Redis.DistributedLock.Redis依赖 二.使用 StackExchange.Redis 对redis操作做简单封装 public ...

  4. wiz 为知笔记服务器 docker 跨服务器迁移爬坑指北

    本文主要是介绍 wiz 为知笔记服务器 docker 从旧服务器迁移到新服务器的步骤以及问题排查. 旧服务器升级 wiz docker 目的:保持和新服务器拉取的镜像版本一致. 官方只留了 wiz d ...

  5. WPF 如何利用Blend给Button添加波纹效果

    先看一下效果吧: 如果不会写动画或者懒得写动画,就直接交给Blend来做吧; 其实Blend操作起来很简单,有点类似于在操作PS,我们只需要设置关键帧,鼠标点来点去就可以了,Blend会自动帮我们生成 ...

  6. 【YashanDB知识库】filter or改写问题

    问题现象 当filter中出现or的时候,会导致filter无法走索引或者走hash join,就需要进行改写,例如: create table test_tab1(col1 int, col2 in ...

  7. SQL Server 语句日期格式查找方法

    1. SQL Server中,处理日期格式和查找特定日期格式方法示例 在SQL Server中,处理日期格式和查找特定日期格式的记录是一个常见的需求.SQL Server提供了多种函数和格式选项来处理 ...

  8. HTTP——请求数据格式

    请求数据格式   

  9. 补天云全网独有技术和唯一实用工具:QT6框架QML源码保护工具应用 QML和JavaScript源码隐藏工具

    如何保护和隐藏你的QT应用中的QML源代码?补天云全网独有技术和唯一实用工具:QT6框架QML源码保护工具应用 QML和JavaScript源码隐藏工具 简介 在通常的QT QML应用程序中,QML语 ...

  10. [OI] 欢夏!邪龙?马拉车!

    标题来自原神 算法概述 Manacher 算法 用途:寻找回文串,最板子的情况下用于字符串的回文子串计数 给定一个字符串 \(S\),求出它全部的回文子串 容易想到一种暴力的 \(n^{2}\) 做法 ...