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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章