当前位置:网站首页>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;
}
边栏推荐
- Application of object detection based on OpenCV and yolov3
- 异步fifo的实现
- spark分区算子partitionBy、coalesce、repartition
- How to update JSON values in the database?
- 死锁杂谈
- Submarine cable detector tss350 (I)
- Recommend 10 learning websites that can be called artifact
- Graph theory and concept
- What is the Internet of things
- redis淘汰策列
猜你喜欢

How to solve the login problem after the 30 day experience period of visual stuido2019

How much memory can a program use at most?

Spark submission parameters -- use of files

ML - Speech - advanced speech model

Debounce and throttle

matlab 如何保存所有运行后的数据

ML - natural language processing - Key Technologies

Ml speech depth neural network model

Node learning

异步fifo的实现
随机推荐
MATLAB读取显示图像时数据格式转换原因
Debounce and throttle
Week303 of leetcode
Notes on inputview and inputaccessoryview of uitextfield
redis淘汰策列
Implementation of asynchronous FIFO
使用cpolar建立一个商业网站(如何购买域名)
How to solve the problem of scanf compilation error in Visual Studio
带你详细认识JS基础语法(建议收藏)
二进制补码
UIDocumentInteractionController UIDocumentPickerViewController
ML - 语音 - 深度神经网络模型
Instance tunnel use
Spark SQL空值Null,NaN判断和处理
Ml speech depth neural network model
How to update JSON values in the database?
CF685B-求有根树每颗子树的重心
自定义注解校验API参数电话号
Tasks, micro tasks, queues and scheduling (animation shows each step of the call)
The number of query results of maxcompute SQL is limited to 1W