洛谷P1197 [JSOI2008]星球大战

题目

由于题目不要求强制在线,所以可以离线。

而离线的话就会带来许多便利,所以我们可以先处理出全部打击后的图,通过并查集来判断是否连通。

然后再从后往前枚举,得出答案

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, m, cnt, k, data[400100], lin[400100], fa[400100], ha[400100];
struct edg {
	int from, to, nex;
}e[601000];
inline void add(int f, int t)
{
	e[++cnt].to = t;
	e[cnt].nex = lin[f];
	lin[f] = cnt;
	e[cnt].from = f;
}
int find(int a)
{
	if (fa[a] == a)	return a;
	return fa[a] = find(fa[a]);
}
inline void uoionn(int a, int b)
{
	int ha = find(a), hb = find(b);
	if (ha != hb)
		fa[ha] = hb;
}
int ans[401000];
signed main()
{
	scanf("%lld%lld", &n, &m);
	for (int i = 0; i <= n; i++)	
		fa[i] = i;
	for (int i = 1; i <= m; i++)
	{
		int x, y;
		scanf("%lld%lld", &x, &y);		
		add(x, y);
		add(y, x);
	}
	scanf("%lld", &k);
	for (int i = 1; i <= k; i++)
		scanf("%lld", &ha[i]), data[ha[i]] = 1;
	int comb = n - k;//comb表示连通块个数,一开始只有n-k个,因为每个没有被打击的点,都是一个连通块
	for (int i = 1; i <= 2 * m; i++)
	{
		if (find (e[i].from) != find (e[i].to) && !data[e[i].from] && !data[e[i].to])//如果这两个点没有相连,且没被摧毁,相当于最小生成树,将其相连
		{
			uoionn(e[i].from, e[i].to);
			comb--;
		}
	}
	ans[k + 1] = comb; 
	for (int i = k; i >= 1; i--)//逐一复原 
	{
		data[ha[i]] = 0;
		comb++;//修复 
		for (int j = lin[ha[i]]; j; j = e[j].nex)
		{	
			int from = e[j].from, to = e[j].to;
			if (!data[to] && find(from) != find(to))//如果没有相连且没被摧毁,就相连
			{
				comb--;	
				uoionn(from, to);
			}
		}
		ans[i] = comb;
	}		
	for (int i = 1; i <= k + 1; i++)
		printf("%lld\n", ans[i]);
}
posted @ 2019-03-31 14:58  DAGGGGGGGGGGGG  阅读(143)  评论(0编辑  收藏  举报