• CF888G Xor-MST


    题目链接

    problem

    给出n个点,每个点有权值,求最小生成树。定义一条边的代价为所连接两点的权值异或值。

    solution

    考虑分治,根据最高位为0还是1分为两部分。然后分别求最小生成树。合并的时候就将最高位为0的一部分插入到trie中,然后从最高位为1的一部分中查询。

    注意对trie的清空。

    code

    /*
    * @Author: wxyww
    * @Date:   2019-08-18 19:36:04
    * @Last Modified time: 2019-08-18 20:20:03
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 200100,INF = 1e9;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    int tree[N * 31][2],a[N];
    int n,tot;
    
    int get(int x) {
    	for(int i = 29;i >= 0;--i) printf("%d",x >> i & 1);
    	puts("");
    }
    void add(int x) {
    	// get(x);
    	int p = 0;
    	for(int i = 29;i >= 0;--i) {
    		int k = x >> i & 1;
    		if(!tree[p][k]) tree[p][k] = ++tot;
    		p = tree[p][k];
    	}
    
    }
    
    int query(int x) {
    	// get(x);
    	int p = 0,ret = 0;
    	for(int i = 29;i >= 0;--i) {
    		int k = x >> i & 1;
    		if(!tree[p][1] && !tree[p][0]) return INF;
    		if(!tree[p][k]) {
    			ret += 1 << i;
    			p = tree[p][k ^ 1];
    		}
    		else p = tree[p][k];
    		
    	}
    	// printf("%d
    ",ret);
    	return ret;
    }
    ll solve(int l,int r,int pos) {
    	if(l > r) return 0;
    	// printf("%d %d %d
    ",l,r,pos);
    	if(l == r || pos == -1) {
    		add(a[l]);
    		return 0;
    	}
    
    	int mid = r;
    	for(int i = l;i <= r;++i) {
    		if(a[i] >> pos & 1) {
    			mid = i - 1;break;
    		}
    	}
    
    
    	ll ret = 0;
    	ret += solve(l,mid,pos - 1);
    
    	int mn = INF;
    
    	for(int i = mid + 1;i <= r;++i) mn = min(mn,query(a[i]));
    
    	if(mn != INF) ret += mn;
    
    	for(int i = 0;i <= tot;++i) tree[i][0] = tree[i][1] = 0;
    	tot = 0;
    
    	ret += solve(mid + 1,r,pos - 1);
    
    	// for(int i = mid + 1;i <= r;++i) add(a[i]);
    	for(int i = l;i <= r;++i) add(a[i]);
    	// printf("%d
    ",ret);
    	// printf("%d %d %d %d
    ",l,r,pos,ret);
    	return ret;
    
    }
    int main() {
    	// freopen("1.in","r",stdin);
    	n = read();
    	for(int i = 1;i <= n;++i) a[i] = read();
    
    	sort(a + 1,a + n + 1);
    
    	// for(int i = 1;i <= n;++i) get(a[i]);
    
     	// puts("");
    
    	cout<<solve(1,n,29);
    
    	return 0;
    }
    
  • 相关阅读:
    python-判断
    python-文件读写
    python-数据类型
    python简介
    Charles--简单使用
    【模拟赛】BYVoid魔兽世界模拟赛 解题报告
    【最短路】埃雷萨拉斯寻宝(eldrethalas) 解题报告
    【递推】地铁重组(subway) 解题报告
    【背包型动态规划】灵魂分流药剂(soultap) 解题报告
    【最短路】血色先锋军(scarlet) 解题报告
  • 原文地址:https://www.cnblogs.com/wxyww/p/CF888G.html
Copyright © 2020-2023  润新知