T on 13 求助
  • 板块CF888G Xor-MST
  • 楼主dark_moon
  • 当前回复0
  • 已保存回复0
  • 发布时间2024/11/20 21:08
  • 上次更新2024/11/20 23:29:46
查看原帖
T on 13 求助
417018
dark_moon楼主2024/11/20 21:08
#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], 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];
        }
        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){
                ans += (1 << i);
                x = to[x][t ^ 1];
            }
            else{
                x = to[x][t];
            }
        }
        return mp(ans, p[x]);
    }
}t;
signed main(){
    for(int i = 1; i <= n; i ++){
        cin >> a[i];
        fa[i] = i;
    }
    int sum = 0;
    while(1){
        sum ++;
        assert(sum <= 20);
        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);
        }
        int tmp = 0;
        // tmp = 1 表示字典树 push 过了
        t.build();
        for(int i = 1; i <= n; i ++){
            if(v[i].size()){
                if(tmp){
                    for(int x : v[i]){
                        to[i] = min(to[i], t.query(x));
                    }
                }
                for(int x : v[i]){
                    t.push(x);
                }
                tmp = 1;
            }
        }
        tmp = 0;
        t.build();
        for(int i = n; i >= 1; i --){
            if(v[i].size()){
                if(tmp){
                    for(int x : v[i]){
                        to[i] = min(to[i], t.query(x));
                    }
                }
                for(int x : v[i]){
                    t.push(x);
                }
                tmp = 1;
            }
        }

        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;
}
2024/11/20 21:08
加载中...