洛谷 P1197 [JSOI2008]星球大战(并查集,建图)

传送门


解题思路

每次删边复杂度太高,所以可以倒序加边。
注意在对方占领后,这个点就不参与连通块数量的计算了。

AC代码

	#include<iostream>
	#include<cstdio>
	#include<cstring>
	#include<cmath>
	#include<algorithm>
	using namespace std;
	const int maxn=4e5+5;
	int n,m,k,a[maxn],p[maxn],cnt,num,fa[maxn],ans[maxn],q[maxn],vis[maxn];
	struct node{
		int v,next;
	}e[maxn];
	void insert(int u,int v){
		num++;
		e[num].v=v;
		e[num].next=p[u];
		p[u]=num;
	}
	int find(int x){ return fa[x]=(fa[x]==x?x:find(fa[x]));}
	int main(){
		ios::sync_with_stdio(false);
		memset(p,-1,sizeof(p));
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			fa[i]=i;
		}
		for(int i=1;i<=m;i++){
			int u,v;
			cin>>u>>v;
			insert(u,v);
			insert(v,u);
		}
		cin>>k;
		for(int i=1;i<=k;i++){
			cin>>q[i];
			vis[q[i]]=1;
		}
		for(int u=0;u<n;u++){
			if(!vis[u]){
				for(int i=p[u];i!=-1;i=e[i].next){
					int v=e[i].v;
					if(vis[v]) continue;
					int f1=find(u),f2=find(v);
					if(f1!=f2){
						fa[f1]=f2;
						cnt++;
					}
				}
			}
		}
		ans[k]=n-k-cnt;
		for(int u=k;u>=1;u--){
			vis[q[u]]=0;
			for(int i=p[q[u]];i!=-1;i=e[i].next){
				int v=e[i].v;
				if(vis[v]) continue;
				int f1=find(q[u]),f2=find(v);
				if(f1!=f2){
					fa[f1]=f2;
					cnt++;
				}
			}
			ans[u-1]=n-(u-1)-cnt;
		}
		for(int i=0;i<=k;i++) cout<<ans[i]<<endl;
		return 0;
	}
原文地址:https://www.cnblogs.com/yinyuqin/p/15292680.html