比赛 round 1『缺混麻酱伞鹊役』 评测结果 AAAAAAAAAA
题目名称 Xor-MST 最终得分 100
用户昵称 darkMoon 运行时间 11.357 s
代码语言 C++ 内存使用 68.18 MiB
提交时间 2024-11-21 09:28:47
显示代码纯文本
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
auto mread = [](){int x;scanf("%d", &x);return x;};
const int N = 2e5 + 5;
int n = mread(), a[N], fa[N];
int findfa(int x){
    if(x == fa[x]){
        return x;
    }
    return fa[x] = findfa(fa[x]);
}
long long ans = 0;
vector<int> v[N];
pair<int, int> to[N];
// to_i 表示 i 这个连通块能连的最小边,fi 是边权,se 是点
struct tree{
    int idx, to[N * 30][2], siz[N * 30], p[N * 30];
    void build(){
        idx = 0;
        to[0][0] = to[0][1] = 0;
        return;
    }
    void push(int id){
        int x = 0;
        for(int i = 30; i >= 0; i --){
            int t = ((a[id] >> i) & 1);
            if(to[x][t] == 0){
                to[x][t] = ++idx;
                to[idx][0] = to[idx][1] = 0;
            }
            x = to[x][t];
            siz[x] ++;
        }
        p[x] = id;
        return;
    }
    pair<int, int> query(int id){
        int ans = 0, x = 0;
        for(int i = 30; i >= 0; i --){
            int t = ((a[id] >> i) & 1);
            if(to[x][t] == 0 || siz[to[x][t]] == 0){
                ans += (1 << i);
                x = to[x][t ^ 1];
            }
            else{
                x = to[x][t];
            }
        }
        return mp(ans, p[x]);
    }
    void erase(int id){
        int x = 0;
        for(int i = 30; i >= 0; i --){
            int t = ((a[id] >> i) & 1);
            if(to[x][t] == 0){
                to[x][t] = ++idx;
                to[idx][0] = to[idx][1] = 0;
            }
            x = to[x][t];
            siz[x] --;
        }
        return;
    }
}t;
signed main(){
    for(int i = 1; i <= n; i ++){
        cin >> a[i];
        fa[i] = i;
    }
    sort(a + 1, a + 1 + n);
    int sum = 0;
    for(int i = 1; i <= n; i ++){
        t.push(i);
    }
    while(1){
        for(int i = 1; i <= n; i ++){
            v[i].clear();
        }
        for(int i = 1; i <= n; i ++){
            v[findfa(i)].push_back(i);
            to[i] = mp(INT_MAX, 0);
        }
        for(int i = 1; i <= n; i ++){
            if(v[i].size()){
                for(int x : v[i]){
                    t.erase(x);
                }
                for(int x : v[i]){
                    to[i] = min(to[i], t.query(x));
                }
                for(int x : v[i]){
                    t.push(x);
                }
            }
        }

        int tmp = 0;
        // tmp 表示有没有连通块向外连边了
        for(int i = 1; i <= n; i ++){
            if(v[i].size()){
                if(to[i].se > 0 && findfa(v[i][0]) != findfa(to[i].se)){
                    tmp = 1;
                    fa[findfa(v[i][0])] = findfa(to[i].se);
                    ans += to[i].fi;
                }
            }
        }
        if(tmp == 0){
            break;
        }
    }
    printf("%lld", ans);
    return 0;
}