[Pregunta solución] Luogu P1197 [JSOI2008] Star Wars

Ir a: Mi propio blog

tema

Luogu P1197 [JSOI2008] La guerra de las galaxias

responder

Para determinar la conectividad de dos planetas y calcular el número de bloques conectados, puede utilizar la búsqueda de unión. Sin embargo, no es fácil eliminar la operación de búsqueda de unión, por lo que debemos considerar el lado opuesto del problema, es decir, partiendo de la situación final, sumar los planetas eliminados uno a uno. Calcule el número de bloques conectados en tiempo real. Si se combinan dos bloques conectados, el número se reduce en uno.

Algunos recordatorios que no tienen nada que ver con el tema en sí: Después de definir el vector <int> v, si el contenedor está vacío, no puede usar v [] = para asignar directamente, si hay más de i elementos en el contenedor (es decir, v [i] existe), puede Acceda a v [i] directamente. No use kill para nombres de variables (¿el mismo nombre que las funciones de biblioteca?).

Código

#include <bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
int n,m,k,cnt; //cnt表示连通块的数量 
bool exist[maxn]; //exist[i]=1表示星球i目前存在(没有被摧毁) 
int fa[maxn],ans[maxn];
vector<int> v[maxn],atk; //v[x]存与x直接相连的点,atk存被摧毁的点 
int find(int x) {return fa[x]<0 ? x : fa[x]=find(fa[x]);}
inline void unite(int r1,int r2) 
{
	fa[r1]<fa[r2] ? fa[r1]+=fa[r2],fa[r2]=r1 : (fa[r2]+=fa[r1],fa[r1]=r2);
}

int main()
{
	scanf("%d%d",&n,&m); 
	memset(fa,-1,sizeof(fa));
	for(int i=1;i<=m;i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		v[x].push_back(y),v[y].push_back(x);
	}
	scanf("%d",&k); cnt=n-k; //最后的局面中,共有n-k个点,若不考虑边,则有n-k个连通块 
	for(int i=0;i<n;i++) exist[i]=1;
	for(int i=1;i<=k;i++) {int t; scanf("%d",&t); exist[t]=0,atk.push_back(t);}
	for(int i=0;i<n;i++)
	{
		if(!exist[i]) continue;
		for(int j=0;j<v[i].size();j++)
		{
			if(!exist[v[i][j]]) continue;
			int r1=find(i),r2=find(v[i][j]);
			if(r1!=r2) unite(r1,r2),cnt--;
		}
	}
	for(int i=k-1;i>=0;i--)
	{
		int x=atk[i];
		ans[i]=cnt,exist[x]=1,cnt++; //注意:多加一个点,就多了一个连通块 
		for(int j=0;j<v[x].size();j++)
		{
			if(!exist[v[x][j]]) continue;
			int r1=find(x),r2=find(v[x][j]);
			if(r1!=r2) unite(r1,r2),cnt--;
		}
	}
	printf("%d\n",cnt);
	for(int i=0;i<k;i++) printf("%d\n",ans[i]);
	
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/zjgmartin/article/details/108425429
Recomendado
Clasificación