CF1305G Kuroni and Antihype

https://www.luogu.com.cn/problem/CF1305G

考虑把边变成 a i + a j a_i+a_j ai+aj,然后答案就是最大生成树-点权和 ∑ a [ i ] \sum a[i] a[i]

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = (1 << 18) + 5;
int fa[N], gs[N], size[N], n;
ll ans;
int get(int x) {
    return fa[x] == x? x : (fa[x] = get(fa[x]));
}
void merge(int x, int y, int xy) {
    x = get(x), y = get(y);
    if(x == y) return ;
    ans += 1ll * (gs[x] + gs[y] - 1) * xy;
    if(size[x] > size[y]) swap(x, y);
    fa[x] = y; size[y] += size[x], gs[y] = 1;
}
int main() {
    scanf("%d", &n);
    ans = 0; gs[0] = 1;
    for(int i = 1; i <= n; i ++) {
        int x;
        scanf("%d", &x);
        gs[x] ++; ans -= x;
    }
    int lim = (1 << 18);
    for(int S = 0; S < lim; S ++) fa[S] = S, size[S] = 1;
    for(int S = lim - 1; S >= 0; S --) {
        for(int x = S; x; x = (x - 1) & S) {
            int y = S ^ x;
            if(!gs[x] || !gs[y]) continue;
            merge(x, y, S);
        }
        if(gs[S]) merge(S, 0, S);
    }
    printf("%lld", ans);

    return 0;
}
posted @ 2021-10-13 14:54  lahlah  阅读(30)  评论(0编辑  收藏  举报