1. 程式人生 > >CF745 C 並查集

CF745 C 並查集

ans space sca names using 初始 將不 並查集 bsp

並查集
由於政府不能連通
我們可以先按給出的邊建立連通塊,再將不含有政府的點全部作為一個連通塊,邊數為(n-1)*n/2
然後 貪心地將該連通塊與[含政府的、且包含點數最多的]連通塊相連,然後由於新增了一些點 所以記得要加上邊
最後減去初始邊即可

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;

int fa[N];
int siz[N];

int find(int x)
{
	if(x != fa[x])
		fa[x] = find(fa[x]);
	return fa[x];
}

int join(int a, int b)
{
	int x = find(a);
	int y = find(b);
	if(x != y)
	{
		fa[x] = y;
		siz[y] += siz[x];
		return 1;
	}
	return 0;
}

int g[N];
int vis[N];
int sum[N];

int main()
{
	int n, m, k;
	while(cin >> n >> m >> k)
	{
		int cnt = 0;
		for(int i = 0; i <= n; i++)
			fa[i] = i, siz[i] = 1;
		for(int i = 0; i < k; i++)
			scanf("%d", g + i);
		for(int i = 0; i < m; i++)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			join(x, y);
		}
		for(int i = 0; i < k; i++)
			vis[find(g[i])] = 1;

		int ma = 0;
		int ans = 0;
		for(int i = 1; i <= n; i++)
		{
			if(find(i) == i)
			{
				if(vis[i] == 1)
					ma = max(ma, siz[i]);
				else sum[cnt++] = siz[i];
				ans += ((siz[i] - 1) * siz[i]) / 2;
			}
		}
		for(int i = 0; i < cnt; i++)
			for(int j = i + 1; j < cnt; j++)
				ans += sum[i] * sum[j];
		int t = 0;
		for(int i = 0; i < cnt; i++)
			t += sum[i];
		printf("%d\n", ans + t*ma - m);
	}
}

CF745 C 並查集