其他分享
首页 > 其他分享> > G. Xor Tree - 字典树

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