标签:Xor ll Tree son dfs2 num const 节点 字典
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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。