[Question Solution] Luogu P1197 [JSOI2008] Star Wars

Go to: My own blog

topic

Luogu P1197 [JSOI2008] Star Wars

answer

To determine the connectivity of two planets and to calculate the number of connected blocks, you can use union search. However, it is not easy to delete the operation of the union search, so we must consider the opposite side of the problem, that is, starting from the final situation, add the eliminated planets one by one. Calculate the number of connected blocks in real time. If two connected blocks are merged, the number is reduced by one.

Some reminders that have nothing to do with the topic itself: After defining vector<int> v, if the container is empty, you cannot use v[]= to assign directly, if there are more than i elements in the container (that is, v[i] exists), it can Access v[i] directly. Do not use kill for variable names (the same name as library functions?).

Code

#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;
}

Guess you like

Origin blog.csdn.net/zjgmartin/article/details/108425429