传送门:hdu 4496
题意:给你n个点和m条边,依次连接这m条边。然后按照输入顺序删除每一条边,问你每次删掉一条边以后的图中的联通块个数。
思路:倒序加边,从一条边都不加到加入m-1条边(因为第一个输出的是删掉第一条边后的结果,所以不加入第一条边)。一条边都不加的时候联通块个数为n,即点的个数。每加入一条边判断这两个点是否拥有同一个父节点,如果不是说明他们在两个不同的联通块中,可以将他们合并,并且联通块个数是加入这条边之前的联通块个数-1;否则说明他们在同一个联通块中,加入这条边不改变联通块个数。
AC代码:
/**********************************************
Author: StupidTurtle
Date: 2018.5.20
Email: 31601359@stu.zucc.edu.cn
**********************************************/
#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 ;
}