CF1305G
题解
考虑对于一个有根树,每条\(fa_v=u\)的边的贡献是\(w_u\),也就是\((w_u+w_v)-w_v\),由于除了根每个\(v\)只有一个\(f_v\),则总贡献就是\(\sum(w_u+w_v)-\sum w_v+w_r\)。
建一个超级根,点权为0,原来每个有根树的根设为这个点的儿子。
那么总贡献就是边权和-点权和。
点权和固定了,边权和可以直接最大生成树算。
int a[1<<18|5];
int dis[1<<18|5],cnt[1<<18|5];
priority_queue<int> pq;
const int m=1<<18;
int fa[1<<18|5];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
ll ans;
void link(int u,int v,int w){
if(cnt[u] && cnt[v]){
u=find(u);v=find(v);
if(u!=v){
ans+=(ll)w*(cnt[u]+cnt[v]-1);fa[u]=v;cnt[v]=1;
}
}
}
signed main(){
#ifdef QAQAutoMaton
freopen("G.in","r",stdin);
freopen("G.out","w",stdout);
#endif
int n;
read(n);
int x;
for(int i=1;i<=n;++i){
read(x);
++cnt[x];
ans-=x;
}
cnt[m]=1;
fa[m]=m;
for(int i=0;i<m;++i){
fa[i]=i;
}
for(int i=m-1;~i;--i){
for(int j=i;;j=(j-1)&i){
link(j,i^j,i);
if(!j)break;
}
link(i,m,i);
}
write(ans,'\n');
return 0;
}