BZOJ 1015: [JSOI2008]星球大战starwar

/*
* 分析:
* 如果是动态使用tarjan求联通分量求缩点个数的话,肯定TLE。
* 我们可以离线把所有要摧毁的星球输入,然后从把所有要摧毁的星球都摧毁之后往摧毁之前
* 建图,使用并查集的方式合并联通块。
* */

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int X = 400005;

#define debug puts("here");

int p[X];

struct node{
	int x,y,next;
}edge[X*2];

int po[X],tol;
bool use[X];
int a[X],tot;
int vec[X];
int n,m;

void add(int x,int y){
	edge[++tol].x = x;
	edge[tol].y = y;
	edge[tol].next = po[x];
	po[x] = tol;
}

int find_set(int x){
	if(x!=p[x])
		p[x] = find_set(p[x]);
	return p[x];
}

void init(){
	memset(po,0,sizeof(po));
	tol = 0;
	for(int i=1;i<=n;i++){
		use[i] = true;
		p[i] = i;
	}
	int x,y;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		x ++;
		y ++;
		add(x,y);
		add(y,x);
	}
	cin >> tot;
	for(int i=1;i<=tot;i++){
		scanf("%d",&a[i]);
		a[i] ++;
		use[a[i]] = false;
	}
}

void solve(){
	int x,y,px,py;
	for(int i=1;i<=tol;i+=2){
		x = edge[i].x;
		y = edge[i].y;
		if(use[x]&&use[y]){
			px = find_set(x);
			py = find_set(y);
			p[px] = py;
		}
	}
	int ans = 0;
	for(int i=1;i<=n;i++)
		if(use[i]&&p[i]==i)
			ans ++;
	for(int i=tot;i;i--){
		vec[i] = ans;
		int x = a[i];
		use[x] = 1;
		ans ++;
		for(int j=po[x];j;j=edge[j].next){
			int y = edge[j].y;
			if(use[y]){
				py = find_set(y);
				px = find_set(x);
				if(px!=py){
					p[px] = py;
					ans --;
				}
			}
		}
	}
	vec[0] = ans;
	for(int i=0;i<=tot;i++)
		printf("%d\n",vec[i]);
}

int main(){
	cin >> n >> m;
	init();
	solve();
	
	return 0;
}

  

原文地址:https://www.cnblogs.com/yejinru/p/2825062.html