当前位置:网站首页>CF888G-巧妙字典树+暴力分治(异或最小生成树)
CF888G-巧妙字典树+暴力分治(异或最小生成树)
2022-07-25 15:23:00 【塔子哥来了】
题目大意
给你一张完全图,任意两个点之间的边权是 a i ⊕ a j a_i\oplus a_j ai⊕aj.问你最小生成树大小
题目思路
看到异或位运算。自然想到字典树.将所有点插入到字典树.看看效果
性质:
令 S i S_i Si为节点 i i i的所有叶子节点在图中所构成的连通块.
1.图中任意两点连边,等价于树上的对应叶子节点 l c a lca lca往下的花费。所以 L C A LCA LCA越深越好
2.任意一个节点,若存在两个儿子 a , b a,b a,b,那么对于将 S a , S b S_a,S_b Sa,Sb联通时,这一位的花费是固定不可避免的.
反之,若只存在一个儿子,连通 S a S_a Sa 本身,这一位的花费是没有的。
所以容易设计出暴力+贪心的方法:
dfs从高位开始遍历所有 含有两个儿子 a , b a,b a,b的节点,然后递归的在 a , b a,b a,b子树里贪心的尽量移动同样的位值。使得花费最小。
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
解释:
最差情况就是 字典树是一颗完全二叉树.这个时候需要枚举n个节点。
递归的复杂度是节点子树大小.
O ( ∑ s z ( i ) ) = O ( ∑ d e p ( i ) ) = O ( ∑ i = 0 l o g n 2 i ∗ i ) = O ( n l o g n ) O(\sum sz(i))=O(\sum dep(i))=O(\sum_{i=0}^{logn}2^i*i)=O(nlogn) O(∑sz(i))=O(∑dep(i))=O(∑i=0logn2i∗i)=O(nlogn)
算法正确性:
根据Brouka算法,
最开始叶子节点合并时,只有当他们不在同一个点时,会产生花费。
第一轮合并连通块后。在字典树上缩点。递归论证.
不难看出上述算法就是Brouka算法的过程。只是逆过来了更好处理。
当然也可以直接模拟B算法,但是需要支持动态开点+合并操作的字典树。复杂度也会比较高.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
const int up = 30;
int a[maxn];
namespace Trie{
int tr[maxn * 20][2] , cnt;
void add (int x){
int u = 0;
for (int i = up ; i >= 0 ; i--){
int v = (x >> i) & 1;
if (!tr[u][v]) tr[u][v] = ++cnt;
u = tr[u][v];
}
}
int ask (int u , int v , int step){
if (step == -1) return 0;
int x = -1 , y = -1;
if (tr[u][0] && tr[v][0]) x = ask(tr[u][0],tr[v][0],step-1);
if (tr[u][1] && tr[v][1]) y = ask(tr[u][1],tr[v][1],step-1);
if (~x && ~y) return min(x , y);
if (~x) return x; if (~y) return y;
x = y = -1;
if (tr[u][0] && tr[v][1]) x = ask(tr[u][0],tr[v][1],step-1) + (1 << step);
if (tr[u][1] && tr[v][0]) y = ask(tr[u][1],tr[v][0],step-1) + (1 << step);
if (~x && ~y) return min(x , y);
if (~x) return x;
return y;
}
ll dfs (int u , int step){
if (step == -1) return 0;
ll ans = 0;
if (tr[u][0] && tr[u][1]){
ans += 1ll * ask(tr[u][0] , tr[u][1] , step - 1) + (1ll << step);
}
if (tr[u][0]) ans += dfs(tr[u][0] , step - 1);
if (tr[u][1]) ans += dfs(tr[u][1] , step - 1);
return ans;
}
}
int main()
{
ios::sync_with_stdio(false);
int n; cin >> n;
for (int i = 1 ; i <= n ; i++) {
int x;cin >> x;
Trie::add(x);
}
cout << Trie::dfs(0 , up) << endl;
return 0;
}
边栏推荐
猜你喜欢

ML - 语音 - 高级语音模型

Example of password strength verification

Spark AQE

ML - 自然语言处理 - 基础知识

解决DBeaver SQL Client 连接phoenix查询超时

matlab--CVX优化工具包安装

matlab---错误使用 var 数据类型无效。第一个输入参数必须为单精度值或双精度值

MySQL installation and configuration super detailed tutorial and simple database and table building method

Idea护眼色设置

Spark partition operators partitionby, coalesce, repartition
随机推荐
Overview of JS synchronous, asynchronous, macro task and micro task
Spark 内存管理机制 新版
看到很多App出现闪烁的图片,特别是会员页面
CGO is realy Cool!
Image cropper example
Solve the timeout of dbeaver SQL client connection Phoenix query
BPSK调制系统MATLAB仿真实现(1)
Spark-SQL UDF函数
How to solve the login problem after the 30 day experience period of visual stuido2019
ML - 语音 - 语音处理介绍
Recommend 10 learning websites that can be called artifact
Implementation of asynchronous FIFO
MySQL installation and configuration super detailed tutorial and simple database and table building method
C#精挑整理知识要点10 泛型(建议收藏)
ML - 自然语言处理 - 自然语言处理简介
args参数解析
Spark获取DataFrame中列的方式--col,$,column,apply
Spark002 --- spark task submission, pass JSON as a parameter
记一次Spark报错:Failed to allocate a page (67108864 bytes), try again.
Delayed loading source code analysis: