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;
}