Codeforces 745C Hongcow Builds A Nation

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/My_stage/article/details/77160736

http://codeforces.com/contest/745/problem/C

题意:
哇,这个题好啊,说的就是,有n个节点,m条边的一个图,这个图里有k个节点是比较牛逼的节点,所以这k个节点不能连接。那么,我想知道我最多还可以再往这个图里加多少条边呢????

思路:
先用并查集做,先记录下牛逼的节点,之后再把m个边连起来。统计下每个集合内元素的个数。因为不牛逼的节点可以和牛逼的节点连接。所以我们标记所有牛逼节点的头目。即find(c[i]),之后我们对于每个是根节点的集合,看他是否牛逼,如果牛逼,我们取最大的牛逼节点的集合。反之我们记录下这个节点的孩子个数。之后我们要加上这个集合的最大边数,即 sum[i]*(sum[i]-1)/2.. 因为我们记录的所有以不牛逼节点为根的集合的数目,这些节点可以相互连接。所以把答案相加。之后我们把这些节点和那个集合数最大的节点相连接。我们得到了这个图的所有边。因为一开始有m边,所以我们要减去m条边。

#include <bits/stdc++.h>
#define maxs 202002
#define mme(i,j) memset(i,j,sizeof(i))
using namespace std;
int fa [maxs];
int sum[maxs];
int c[maxs];

int findfa(int x){
    return x==fa[x]?fa[x]:fa[x] = findfa(fa[x]);
}

void joint(int x,int y){
    int rx=findfa(x),ry=findfa(y);
    if(rx!=ry)
    {
        fa[rx]=ry;
        sum[ry]+=sum[rx];
    }
}

bool vis[maxs];
vector<int>vec;

int main(){
    int n,m,k;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        vec.clear();
        for(int i=0;i<=n;i++) {
                fa[i]=i;
                sum[i]=1;
        }
        for(int i=0;i<k;i++)
            scanf("%d",&c[i]);


        int x,y;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&x,&y);
            joint(x,y);
        }
        mme(vis,0);
        for(int i=0;i<k;i++)
            vis[findfa(c[i])]=1;
        int mx=-1;
        long long ans=0;

        for(int i=1;i<=n;i++){
            if(fa[i]==i){
                if(vis[i]==1)
                  mx = max(mx,sum[i]);
                else
                    vec.push_back(sum[i]);

                ans+=sum[i]*(sum[i]-1)/2;
            }
        }
        int sz = vec.size();
        for(int i=0;i<sz;i++)
        {
            for(int j=i+1;j<sz;j++){
                ans+=vec[i]*vec[j];
            }
            ans+=vec[i]*mx;
        }
        ans-=m;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/My_stage/article/details/77160736