2020年ccpc威海(祖先的边权和点权)

传输门

给出了 n 个人和 m 条关系,每一个团体的价值为当前团体的关系数-人数,如果这个团体的关系数小于等于人数那么就是 0 ,也就相当于不选择。

可以使用并查集来考虑对于每个节点计算点数和边数的关系,符合边数-点数>0的就加上边数-点数,最后求总和。

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+100;
int pre[maxn];
int p[maxn];
int z[maxn];
int find(int x) {
    if (pre[x] == x) return x;
    return pre[x] = find(pre[x]);
}

void marge(int a,int b){
    int t1=find(a);
    int t2=find(b);
    p[t2]++;
    if(t1!=t2)
    {
        pre[t1]=t2;
        p[t2]+=p[t1];
        z[t2]+=z[t1];
    }
    
}
int a[maxn],b[maxn];
int main(){
    int t,n,m;
    cin>>t;
    int kase=0;
    while(t--){
        scanf("%d%d",&n,&m); 
        for(int i=1;i<=n;i++){
            p[i]=0;
            z[i]=1; 
            pre[i]=i;    
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a[i],&b[i]);
            marge(a[i],b[i]);
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(pre[i]==i)
                ans+=max(0,p[i]-z[i]);
        }
        printf("Case #%d: ",++kase);
        cout<<ans<<endl;
    }
    
}
原文地址:https://www.cnblogs.com/lipu123/p/13900031.html