p1197 星球大战 (并查集)

题目描述

很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系。

某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直接或间接地连接。

但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。

现在,反抗军首领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通块的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一个连通块中)。

输入格式

输入文件第一行包含两个整数,NNN (1<=N<=2M1 < = N < = 2M1<=N<=2M) 和 MMM (1<=M<=200,0001 < = M < = 200,0001<=M<=200,000),分别表示星球的数目和以太隧道的数目。星球用 000 ~ N−1N-1N−1 的整数编号。

接下来的 MMM 行,每行包括两个整数 XXX, YYY,其中( 0<=X<>Y0 < = X <> Y0<=X<>Y 表示星球 xxx 和星球 yyy 之间有 “以太” 隧道,可以直接通讯。

接下来的一行为一个整数 kkk ,表示将遭受攻击的星球的数目。

接下来的 kkk 行,每行有一个整数,按照顺序列出了帝国军的攻击目标。这 kkk 个数互不相同,且都在 000 到 n−1n-1n−1 的范围内。

输出格式

第一行是开始时星球的连通块个数。接下来的 KKK 行,每行一个整数,表示经过该次打击后现存星球的连通块个数。

输入输出样例

输入

8 13
0 1
1 6
6 5
5 0
0 6
1 2
2 3
3 4
4 5
7 1
7 2
7 6
3 6
5
1
6
3
5
7

输出

1
1
1
2
3
3

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;

const int maxn = 4e5 + 10;
int father[maxn];
int head[maxn];
int ans[maxn];
int n, m, cnt;
int broken[maxn], vis[maxn];
vector<int>v[maxn];

struct node{
	int u, v, nex;
}edge[maxn];

void addedge(int u, int v)
{
	edge[++cnt].u = u;
	edge[cnt].v = v;
	edge[cnt].nex = head[u];
	head[u] = cnt;
}

int find(int x)
{
	int tem = x;
	while(x != father[x])
		x = father[x];
	while(tem != x)
	{
		int z = tem;
		tem = father[z];
		father[z] = x;
	}
	return x;
}

void Union(int x, int y)
{
	int fx= find(x);
	int fy = find(y);
	if(fx != fy)
		father[fy] = fx;
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin >> n >> m;
	scanf("%d%d", &n, &m);
	for(int i = 0; i <= n; i++)
		father[i] = i;
	memset(head, -1, sizeof(head));
	int x, y;
	for(int i = 1; i <= m; i++) {
//		cin >> x >> y;
		scanf("%d%d", &x, &y);
		addedge(x, y);
		addedge(y, x);
	}
	int k ;
//	cin >> k;
	scanf("%d", &k);
	int all = n - k;
	for(int i = 1; i <= k; i++) {
		scanf("%d", &broken[i]);	
//		cin >> broken[i];
		vis[broken[i]] = 1;
	}
//	cout << all << " ";
	for(int i = 1; i <= 2 * m; i++) {
		int u = edge[i].u, v = edge[i].v;
		if(vis[u] == 0 && vis[v] == 0 && find(u) != find(v)) {
			all--;
			Union(u, v);
		}
	}
//	cout << all << endl;
	ans[k + 1] = all;
	for(int i = k; i >= 1; i--)
	{
		int u = broken[i];
		vis[u] = 0;
		all++;
		for(int j = head[u]; j != -1; j = edge[j].nex) {
			int v = edge[j].v;
			if(vis[v] == 0 && find(u) != find(v))
				all--, Union(u, v);
		}
		ans[i] = all;
	}
	for(int i = 1; i <= k + 1; i++)
		printf("%d\n", ans[i]);
//		cout << ans[i] << endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章