hdu 4496 - D-City (基础并查集)

传送门:hdu 4496


题意:给你n个点和m条边,依次连接这m条边。然后按照输入顺序删除每一条边,问你每次删掉一条边以后的图中的联通块个数。


思路:倒序加边,从一条边都不加到加入m-1条边(因为第一个输出的是删掉第一条边后的结果,所以不加入第一条边)。一条边都不加的时候联通块个数为n,即点的个数。每加入一条边判断这两个点是否拥有同一个父节点,如果不是说明他们在两个不同的联通块中,可以将他们合并,并且联通块个数是加入这条边之前的联通块个数-1;否则说明他们在同一个联通块中,加入这条边不改变联通块个数。


AC代码:

/**********************************************
	Author:		StupidTurtle
	Date:		2018.5.20
	Email:		[email protected]
**********************************************/

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

using namespace std;

typedef long long ll ;
const int oo = 0x7f7f7f7f ;
const int maxn = 1e4 + 7 ;
const int maxm = 1e5 + 7 ;
const int mod = 1e9 + 7 ;

int pre[maxn] , ans[maxm] ;

int Find ( int x ){
	return x == pre[x] ? pre[x] : pre[x] = Find(pre[x]) ;
}

struct node{
	int u , v ;
};

node p[maxm] ;

int main(void){
	
	int n , m ;
	while ( ~scanf("%d%d",&n,&m ) ){
		for ( int i = 0 ; i < n ; i ++ ){
			pre[i] = i ;
		}
		for ( int i = 0 ; i < m ; i ++ ){
			scanf("%d%d",&p[i].u,&p[i].v );
		}
		ans[m] = n ;
		for ( int i = m - 1 ; i > 0 ; i -- ){
			if ( ans[i+1] == 1 ){
				ans[i] = 1 ;
				continue ;
			}
			int fu = Find(p[i].u) , fv = Find(p[i].v) ;
			if ( fu == fv ){
				ans[i] = ans[i+1] ;
			} else {
				pre[fu] = fv ;
				ans[i] = ans[i+1] - 1 ;
			}
		}
		for ( int i = 1 ; i <= m ; i ++ ){
			printf("%d\n",ans[i] );
		}
	}
	
	return 0 ;
}

猜你喜欢

转载自blog.csdn.net/stupid_turtle/article/details/80381287