• 【题解】【CF】CF888G Xor-MST


    CF888 G Xor-MST

    CF888 G Xor-MST

    1 杂言

    一看到MST,立即想到kruskal,立即想到暴力跑边,立即想到TLE,立即放弃了这道题。蒟蒻的想象惟在这一层能够如此跃进

    2 题解

    首先,看到异或,就要用trie

    接下来考虑一个(比较冷)的最小生成树算法:Borůvka算法

    算法介绍

    先把所有节点的权值加入01trie

    对于任意一个非叶子节点(p) ,它的0子树和1子树一定没有联通

    大致证明是,考虑连接这0子树和1子树的花费至少为(2^a) ,而一边若还有没有联通的块,花费必然小于(2^a) ,因此会先连接这两块((a) 为(p) 的深度)

    那么,在两个子树分别联通之后,我们只需要找到最小代价联通两个子树的边即可,这部分用trie解决

    接下来,两个子树分别联通的代价可以用同样的方法分别计算

    也就是说,这个trie是B算法的分治树

    按这个思路分治下去即可

    3 code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #define int long long
    using namespace std;
    
    const int N=200010;
    
    inline void read(int &x) {
        x=0;
        int f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9') {
            if (ch=='-') {
                f=-1;
            }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') {
            x=x*10+ch-'0';
            ch=getchar();
        }
        x*=f;
    }
    
    vector<int> a;
    
    struct note {
        int ch[2];
    };
    
    note t[N<<5];
    int siz;
    
    inline void insert(int &o,int val,int p) {
        if (!o) {
            o=++siz;
        }
        if (p==-1) {
            return;
        }
        int k=(val>>p)&1;
        insert(t[o].ch[k],val,p-1);
    }
    
    int query(int o,int val,int p) {
        if (p==-1) {
            return 0;
        }
        int k=(val>>p)&1;
        return (t[o].ch[k]?query(t[o].ch[k],val,p-1):query(t[o].ch[!k],val,p-1)^(1<<p));
    }
    
    int solve(vector<int> v,int o,int p) {
        if (!o) {
            return 0;
        }
        int len=v.size();
        vector<int> ve[2];
        for(int i=0;i<len;i++){
            ve[(v[i]>>p)&1].push_back(v[i]);
        }
        if (!ve[0].size()) {
            return solve(ve[1],t[o].ch[1],p-1);
        }
        if (!ve[1].size()) {
            return solve(ve[0],t[o].ch[0],p-1);
        }
        len=ve[1].size();
        int cst=2147483647;
        for(int i=0;i<len;i++) {
            cst=min(cst,(1<<p)+query(t[o].ch[0],ve[1][i],p-1));
        }
        return cst+solve(ve[1],t[o].ch[1],p-1)+solve(ve[0],t[o].ch[0],p-1);
    }
    
    int n;
    int rt;
    
    signed main() {
        read(n);
        rt=0;
        for(int i=1;i<=n;i++) {
            int x;
            read(x);
            a.push_back(x);
            insert(rt,x,30);
        }
        printf("%lld
    ",solve(a,rt,30));
        return 0;
    }
    

    Author: tt66ea

    Created: 2021-01-22 周五 15:56

    Validate

  • 相关阅读:
    Excel标题与索引的对应关系
    拼接LINQ动态表达式
    根据输入的模型属性表达式获取名称
    如何将页面的<br/>在Excel中正确换行
    针对VM从挂机-启动后,docker相关服务的无法使用问题!
    NIO(三):Selector选择器
    NIO(二):Channel通道
    Netty(一):netty的入门使用。
    设计模式(五):原型模式
    NIO(一):Buffer缓冲区
  • 原文地址:https://www.cnblogs.com/tt66ea-blog/p/14313795.html
Copyright © 2020-2023  润新知