Loading

【题解】【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\n",solve(a,rt,30));
    return 0;
}

Author: tt66ea

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

Validate

posted @ 2021-01-22 15:54  tt66ea蒟蒻  阅读(127)  评论(0编辑  收藏  举报