其他分享
首页 > 其他分享> > 图论练习

图论练习

作者:互联网

目录

CF888G Xor-MST

题意

思路

看到异或,想到 01trie线性基

线性基明显不大行,考虑 01trie

先将每个节点的权值插入 \(trie\) 中,如下图

容易发现,若是两个点连边,权值就是 \(lca\) 以下的边的异或值

考虑深度最大的 \(lca\),可以发现,若是 \(a_i\) 两两不同,那么有且仅有 \(n-1\) 个这样的 \(lca\)

最好的结果就是将这 \(n-1\) 个 \(lca\) 以下的边的值贪心的算出来

贪心:尽量让高位的 \(1/0\) 相同,使得两个值 \(xor\) 的结果尽量小

\(dfs\) 一遍找到所有有两个儿子的节点搞贪心即可

#include<bits/stdc++.h>
using namespace std;

const int inf=1<<30;
const int N=6e6+5;

#define ll long long

int n,tot;
int t[N][2];
ll ans;

inline void insert(int x){
	int rt=0;
	for(int i=30;i>=0;--i){
		int c=(1<<i)&x?1:0;
		if(!t[rt][c]) t[rt][c]=++tot;
		rt=t[rt][c];
	}
}

inline ll get_mn(int l,int r,int dep){
	if(dep<0) return 0;
	ll a1=inf,a2=inf;
	if(t[l][0]&&t[r][0]) a1=get_mn(t[l][0],t[r][0],dep-1);
	if(t[l][1]&&t[r][1]) a2=get_mn(t[l][1],t[r][1],dep-1);
	if(a1!=inf||a2!=inf) return min(a1,a2);
	if(t[l][0]&&t[r][1]) a1=get_mn(t[l][0],t[r][1],dep-1)+(1<<dep);
	if(t[l][1]&&t[r][0]) a2=get_mn(t[l][1],t[r][0],dep-1)+(1<<dep);
	return min(a1,a2);
}

inline void dfs(int rt,int dep){
	if(dep<0) return;
	if(t[rt][0]&&t[rt][1]) ans+=get_mn(t[rt][0],t[rt][1],dep-1)+(1<<dep);
	if(t[rt][0]) dfs(t[rt][0],dep-1);
	if(t[rt][1]) dfs(t[rt][1],dep-1);
}

signed main(){
	ios::sync_with_stdio(0);
	cin>>n;
	for(int i=1,x;i<=n;++i){
		cin>>x;
		insert(x);
	}
	dfs(0,30);
	cout<<ans<<endl;
}

标签:图论,le,int,lca,练习,结点,权值,贪心
来源: https://www.cnblogs.com/into-qwq/p/16450135.html