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;

}

  

 

你可能感兴趣的:(2008)