CF888G Xor-MST(01trie,MST)

前沿

刚学习了 Borůvka 生成树算法,去写几道题,结果这道题用的是 01Trie,可能是用到了这个算法的思想吧。

题目链接

题目大意

\(n\) 个点的无向完全图,每条边的权值定义为它两个端点的异或值,求这个图的最小生成树

题目解析

生成树算法一般有 Kruskal,Prim 和 Borůvka 算法,一般对于边权是由点权0转变过来的求 MST 的题目,一般采用 Borůvka 求解。

Borůvka 是一种维护联通块,每轮连多条边的算法,因为最多只会进行 \(log\) 轮,所以复杂度是 \(mlogn\) 的,当我们用一些数据结构维护后,复杂度可以降低,从而达到通过本题的复杂度。

当然一些题只是用的此算法的思想,并没有真正的在代码上写出此算法。

回到本题,我们显然可以建一棵 01Trie 出来。

我们发现如果两个节点共同的部分(即 01trie 上的lca)深度越深,显然它们的异或值越小,所以我们可以利用贪心的思想,即在trie树上贪心。

对于当前的一个节点,如果它的左右儿子都存在,那么显然左子树和右子树一定会在此节点去合并成一个集合,那么我们可以去找到左子树和右子树中的哪两个值异或的值最小,但是这样显然复杂度是不对劲的。

所以我们可以采用启发式合并的思想,每次把小的去往大的里面找,这样就可以做到正常复杂度,复杂度大概是 \(O(nlog^2n)\)

在合并两棵子树时, 我们把 size 较小的那棵树的所有节点拿出来, 然后在另一棵子树上贪心地走, 最后对较小子树的所有节点的结果取一个最小值就好了。

相当于一棵 01Trie 在 另一棵 01Trie 上去匹配。

题目代码

// by longdie 
#include <bits/stdc++.h> 
#define ll long long 
using namespace std;
const int N = 2e5 + 5; 
ll Min; 
int n, tot, ch[N*20][2], siz[N*20];
void ins(int x) {
	int now = 0; siz[now]++; 
	for(register int i = 29; i >= 0; --i) {
		int c = (x >> i & 1); 
		if(!ch[now][c]) ch[now][c] = ++tot; 
		now = ch[now][c], siz[now]++; 
	}
}
void merge(int u, int v, int dep, ll sum) {
	if(sum >= Min) return; 
	if(dep < 0) { Min = min(Min, sum); return; } 
	if(ch[u][0]) {
		if(ch[v][0]) merge(ch[u][0], ch[v][0], dep-1, sum); 
		else if(ch[v][1]) merge(ch[u][0], ch[v][1], dep-1, sum+(1<<dep)); 
	}
	if(ch[u][1]) {
		if(ch[v][1]) merge(ch[u][1], ch[v][1], dep-1, sum); 
		else if(ch[v][0]) merge(ch[u][1], ch[v][0], dep-1, sum+(1<<dep)); 
	}
}
ll query(int u, int dep) {
	if(dep < 0) return 0; 
	ll res = 0; 
	if(ch[u][0]) res += query(ch[u][0], dep - 1);
	if(ch[u][1]) res += query(ch[u][1], dep - 1);
	if(ch[u][0] && ch[u][1]) {
		res += 1 << dep, Min = 0x3f3f3f3f3f3f3f3f; 
		if(siz[ch[u][0]] <= siz[ch[u][1]]) merge(ch[u][0], ch[u][1], dep - 1, 0); 	
		else merge(ch[u][1], ch[u][0], dep - 1, 0); 
		res += Min; 
	}
	return res; 
}
signed main() {
	scanf("%d", &n); 
	for(register int i = 1; i <= n; ++i) {
		int x; scanf("%d", &x), ins(x); 
	}
	printf("%lld\n", query(0, 29)); 
	return 0; 
}

posted @ 2021-03-09 17:39  longdie  阅读(77)  评论(0编辑  收藏  举报