G. Xor Tree - 字典树
作者:互联网
G. Xor Tree
https://codeforces.ml/group/MKpYqfAQQQ/contest/386972/problem/G
题意
给一个数组里面的数都不相同 对于每个数组中的数 找到数组中与之亦或值最小的数 这两个数之间有一条边
求最多删去多少个数 使得最后得到的图是连通图
思路
字典树
处理每个数的二进制数 根据01串的情况 生成一颗二叉字典树 更新节点时 同时更新该点能掌管的叶子结点数
两个数越接近 亦或值就越小 对于相邻的两个节点的亦或值是最小的 所以两个相邻的节点一定能在一个连通块里
所以对于每个节点 如果有两个儿子节点 那就比较两个节点掌管的叶节点数量 将少的删到1 多的保留(非同一子树的叶子节点 当那颗子树只剩下一个叶子节点的时候 他就会和另一颗子树上的叶节点相连 否则还是同一颗子树相连)
应该从下往上遍历 达到最贪
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<unordered_map>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const ll N = 2e5 + 5;
const int M = 1e6 + 5;
const ll mod = 1e9 + 7;
ll n, k, q, ans;
ll a[N], cnt[N << 5], tot, son[N << 5][2];
//插入 记录每个数的二进制位 生成一颗字典树
void insert(ll x) {
ll p = 0;
for (int i = 31; i >= 0; i--) {
ll num = 1ll & (x >> i);
if (!son[p][num])
son[p][num] = ++tot;
cnt[son[p][num]]++;
p = son[p][num];
}
}
//求要保留的
ll dfs2(ll x) {
if (!son[x][1] && !son[x][0]) return 1;
if (son[x][1] && son[x][0]) {
ll a = dfs2(son[x][1]);
ll b = dfs2(son[x][0]);
//保留最大的并将较小的那个变为1
return max(a, b) + 1;
}
else {
ll num = son[x][1] ? son[x][1] : son[x][0];
return dfs2(num);
}
}
void solve() {
cin >> n;
tot = 0;
ans = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
insert(a[i]);
}
ll xx = dfs2(0);
cout << n - xx << '\n';
}
signed main() {
IOS;
int t = 1;
//cin >> t;
while (t--) {
solve();
}
}
标签:Xor,ll,Tree,son,dfs2,num,const,节点,字典 来源: https://www.cnblogs.com/yaqu-qxyq/p/16476207.html