Codeforces 744A. Hongcow Builds A Nation

A. Hongcow Builds A Nation

题意: 现在有 n 个点 ,m 条边组成了一个无向图 , 其中有 k 个特殊点, 这些特殊点之间不能连通 ,问可以再多加几条边?

因为$x^2+y^2<=(x+y)^2$,所以找出所有连通块,枚举一个特殊连通块,与其他非特殊连通块合在一起。一个连通块贡献答案:$\frac{Size^2-Size}{2}-已有边$

 

#include< cstdio >

typedef long long ll;
template
inline void read(T&x)
{
	x=0;bool f=0;char c=getchar();
	while((c<'0'||c>'9')&&c!='-') c=getchar();if(c=='-')f=1, c=getchar();
	while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
	x=f?-x:x;
}
const int MAXN(1010);
int n,m,k,a,b,f[MAXN],c[MAXN],size[MAXN],have[MAXN],que[MAXN],tl,Ans,tmp,now;
bool bf[MAXN];
int gf(int x){return x==f[x]?x:f[x]=gf(f[x]);}
int max(int a,int b){return a>b?a:b;}
void Union(int a,int b)
{
	int fa=gf(a),fb=gf(b);
	if(fa!=fb)
	{
		size[fa]+=size[fb];
		have[fa]+=have[fb];
		f[fb]=fa;
	}
	have[fa]++;
}
int Edge(int x)
{
	return (size[x]*(size[x]-1))/2-have[x];
}
int main()
{
//	freopen("C.in","r",stdin);
//	freopen("C.out","w",stdout);
	read(n);read(m);read(k);
	for(int i=1;i<=n;i++)f[i]=i,size[i]=1;
	for(int i=1;i<=k;i++)read(c[i]);
	for(int i=1;i<=m;i++)
	{
		read(a);read(b); Union(a,b);
	}
	for(int i=1;i<=n;i++)
	if(!bf[gf(i)])que[++tl]=gf(i),bf[gf(i)]=1;
	for(int i=1;i<=k;i++)
	{
		bf[gf(c[i])]=0;
		Ans+=Edge(gf(c[i]));
	}
//	fprintf(stderr,"%d\n",tl);
	for(int i=1;i<=tl;i++)
	if(bf[que[i]])
	{
		size[0]+=size[que[i]];
		have[0]+=have[que[i]];
	}
//	fprintf(stderr,"Ans%d\n",Ans);
//	fprintf(stderr,"0:%d\n",Edge(0));
	now=Ans;
	for(int i=1;i<=k;i++)
	{
		tmp=now;
		size[0]+=size[gf(c[i])];
		have[0]+=have[gf(c[i])];
		tmp-=Edge(gf(c[i]));
		tmp+=Edge(0);
//		fprintf(stderr,"s0:%d\n",size[0]);
//		fprintf(stderr,"h0:%d\n",have[0]);
//		fprintf(stderr,"e0:%d\n",Edge(0));
//		fprintf(stderr,"tmp:%d\n",tmp);
		size[0]-=size[gf(c[i])];
		have[0]-=have[gf(c[i])];		
		Ans=max(Ans,tmp);
	}
	printf("%d\n",Ans);
	return 0;
}
posted @ 2017-06-05 18:39  Oncle_Ha  阅读(265)  评论(0编辑  收藏  举报